/**
 * Blog/Publishing Data Domain Example
 *
 * This file demonstrates how to create a comprehensive blog/publishing data domain
 * using the API Client Core modeling system. It follows the business-first approach
 * and demonstrates proper use of namespaces, models, entities, properties,
 * associations, and semantic annotations.
 *
 * The example includes:
 * - Content Management with posts, pages, and media
 * - User Management with authors, editors, and subscribers
 * - Publishing Workflow with drafts, reviews, and publication
 * - Social Features with comments, likes, and sharing
 * - Analytics and SEO with metadata and tracking
 * - Multi-tenant support for multiple blogs/publications
 *
 * @example
 * ```typescript
 * import { createBlogDomain } from './blog-domain.js'
 *
 * const domain = createBlogDomain()
 * console.log('Blog domain created with', domain.graph.nodeCount(), 'nodes')
 * ```
 */

import { DataDomain } from '../../../DataDomain.js'
import { SemanticType } from '../../../Semantics.js'
import { createCalculatedSemantic } from '../../../definitions/Calculated.js'
import { createURLSemantic } from '../../../definitions/URL.js'
import {
  addIdField,
  addNameField,
  addDescriptionField,
  addPublicUniqueNameField,
  addCustomStatusField,
  addCreatedAtField,
  addUpdatedAtField,
  addEmailField,
  addPasswordField,
  addFirstNameField,
  addLastNameField,
  addAvatarUrlField,
  addBooleanField,
  addQuantityField,
} from '../../../helpers/Intelisense.js'
import type { CreateTemplateOptions } from '../../types.js'

function createDomain(): DataDomain {
  return new DataDomain({
    info: {
      name: 'Blog Publishing Platform',
      displayName: 'Blog Publishing Platform',
      description:
        'A comprehensive content management and publishing platform for blogs, magazines, and digital publications',
    },
  })
}

/**
 * Creates a comprehensive blog/publishing data domain following domain-driven design principles.
 *
 * This function demonstrates the proper hierarchy and organization for a publishing platform:
 * 1. Creates the root DataDomain for the publishing platform
 * 2. Organizes functionality into logical namespaces (Content, Users, Publishing, etc.)
 * 3. Groups related entities into models within each namespace
 * 4. Defines entities with proper semantic annotations for publishing workflows
 * 5. Establishes associations with appropriate cardinality for content relationships
 *
 * @returns A fully configured DataDomain with all blog/publishing entities and relationships
 */
export default function createBlogDomain(options: CreateTemplateOptions = {}): DataDomain {
  // Ensure the root data domain
  const domain = options.domain ?? createDomain()

  //
  // 1. CONTENT MANAGEMENT NAMESPACE
  //
  const contentManagement = domain.addNamespace({
    info: {
      name: 'ContentManagement',
      displayName: 'Content Management',
      description: 'Core content creation, editing, and organization features',
    },
  })

  // Publication Model - Multi-tenant support
  const publicationModel = contentManagement.addModel({
    info: {
      name: 'Publications',
      displayName: 'Publications Management',
      description: 'Individual blogs, magazines, or publications within the platform',
    },
  })

  // Publication Entity - Represents individual blogs/publications
  const publicationEntity = publicationModel.addEntity({
    info: {
      name: 'publication',
      displayName: 'Publication',
      description: 'Individual blog or publication site',
    },
  })

  addIdField(publicationEntity, { displayName: 'Publication ID', description: 'Unique identifier for the publication' })

  addNameField(publicationEntity, { displayName: 'Publication Name', description: 'Display name of the publication' })

  addPublicUniqueNameField(publicationEntity, {
    name: 'slug',
    displayName: 'URL Slug',
    description: 'URL-friendly identifier for the publication',
  })

  addDescriptionField(publicationEntity, { description: 'Publication description and tagline' })

  publicationEntity.addProperty({
    info: { name: 'domain', displayName: 'Custom Domain', description: 'Custom domain name for the publication' },
    type: 'string',
    // semantics: [{ id: SemanticType.DomainName }],
  })

  publicationEntity.addProperty({
    info: { name: 'logo_url', displayName: 'Logo URL', description: 'URL to publication logo image' },
    type: 'string',
    semantics: [{ id: SemanticType.ImageURL }],
  })

  addCustomStatusField(publicationEntity, ['active', 'suspended', 'archived'], {
    displayName: 'Publication Status',
    description: 'Current status of the publication',
  })

  addCreatedAtField(publicationEntity, { description: 'When the publication was created' })

  // Content Model
  const contentModel = contentManagement.addModel({
    info: {
      name: 'Content',
      displayName: 'Content Management',
      description: 'Posts, pages, and other content types',
    },
  })

  // Category Entity
  const categoryEntity = contentModel.addEntity({
    info: {
      name: 'category',
      displayName: 'Content Category',
      description: 'Content categorization for organization and navigation',
    },
  })

  addIdField(categoryEntity, { displayName: 'Category ID', description: 'Unique identifier for the category' })

  addNameField(categoryEntity, { displayName: 'Category Name', description: 'Display name of the category' })

  addPublicUniqueNameField(categoryEntity, {
    name: 'slug',
    displayName: 'URL Slug',
    description: 'URL-friendly identifier for the category',
  })

  addDescriptionField(categoryEntity, { description: 'Category description' })

  categoryEntity.addProperty({
    info: { name: 'color', displayName: 'Color', description: 'Theme color for the category' },
    type: 'string',
    // semantics: [{ id: SemanticType.Color }],
  })

  // Category-Publication Association (Many-to-One)
  categoryEntity.addAssociation(
    { key: publicationEntity.key },
    {
      info: { name: 'publication', displayName: 'Publication', description: 'Publication this category belongs to' },
      required: true,
      multiple: false,
    }
  )

  // Self-referencing association for category hierarchy
  categoryEntity.addAssociation(
    { key: categoryEntity.key },
    {
      info: {
        name: 'parentCategory',
        displayName: 'Parent Category',
        description: 'Parent category for hierarchical organization',
      },
      required: false,
      multiple: false,
    }
  )

  // Tag Entity
  const tagEntity = contentModel.addEntity({
    info: {
      name: 'Tag',
      displayName: 'Content Tag',
      description: 'Tags for flexible content labeling and discovery',
    },
  })

  addIdField(tagEntity, { displayName: 'Tag ID', description: 'Unique identifier for the tag' })

  addNameField(tagEntity, { displayName: 'Tag Name', description: 'Display name of the tag' })

  addPublicUniqueNameField(tagEntity, {
    name: 'slug',
    displayName: 'URL Slug',
    description: 'URL-friendly identifier for the tag',
  })

  // Tag-Publication Association (Many-to-One)
  tagEntity.addAssociation(
    { key: publicationEntity.key },
    {
      info: { name: 'publication', displayName: 'Publication', description: 'Publication this tag belongs to' },
      required: true,
      multiple: false,
    }
  )

  // Post Entity - Main content type
  const postEntity = contentModel.addEntity({
    info: {
      name: 'Post',
      displayName: 'Blog Post',
      description: 'Individual blog posts and articles',
    },
  })

  addIdField(postEntity, { displayName: 'Post ID', description: 'Unique identifier for the post' })

  postEntity.addProperty({
    info: { name: 'title', displayName: 'Post Title', description: 'Title of the blog post' },
    type: 'string',
    required: true,
    semantics: [{ id: SemanticType.Title }],
  })

  addPublicUniqueNameField(postEntity, {
    name: 'slug',
    displayName: 'URL Slug',
    description: 'URL-friendly identifier for the post',
  })

  postEntity.addProperty({
    info: { name: 'excerpt', displayName: 'Excerpt', description: 'Brief summary or excerpt of the post' },
    type: 'string',
    semantics: [{ id: SemanticType.Summary }],
  })

  const postContent = postEntity.addProperty({
    info: { name: 'content', displayName: 'Content', description: 'Full content of the post in HTML or Markdown' },
    type: 'string',
    required: true,
    semantics: [{ id: SemanticType.HTML }],
  })

  postEntity.addProperty({
    info: {
      name: 'content_format',
      displayName: 'Content Format',
      description: 'Format of the content (HTML, Markdown, etc.)',
    },
    type: 'string',
    required: true,
    schema: {
      enum: ['html', 'markdown', 'richtext'],
      defaultValue: { type: 'literal', value: 'markdown' },
    },
  })

  postEntity.addProperty({
    info: { name: 'featured_image_url', displayName: 'Featured Image URL', description: 'URL to featured image' },
    type: 'string',
    semantics: [{ id: SemanticType.ImageURL }],
  })

  addCustomStatusField(postEntity, ['draft', 'pending_review', 'scheduled', 'published', 'archived'], {
    displayName: 'Post Status',
    description: 'Current publishing status of the post',
  })

  addCreatedAtField(postEntity, {
    name: 'published_at',
    displayName: 'Published At',
    description: 'When the post was published',
  })

  postEntity.addProperty({
    info: {
      name: 'scheduled_at',
      displayName: 'Scheduled At',
      description: 'When the post is scheduled to be published',
    },
    type: 'datetime',
  })

  addQuantityField(postEntity, {
    name: 'view_count',
    displayName: 'View Count',
    description: 'Number of times the post has been viewed',
  })

  postEntity.addProperty({
    info: { name: 'reading_time', displayName: 'Reading Time', description: 'Estimated reading time in minutes' },
    type: 'number',
    readOnly: true,
    semantics: [
      createCalculatedSemantic({
        formula: `CEIL(LENGTH(REPLACE({{${postContent.key}}}, " ", "")) / 250)`,
        dependencies: [postContent.key],
        recalculateOnUpdate: true,
      }),
    ],
  })

  postEntity.addProperty({
    info: { name: 'word_count', displayName: 'Word Count', description: 'Number of words in the post content' },
    type: 'number',
    readOnly: true,
    semantics: [
      createCalculatedSemantic({
        formula: `LENGTH({{${postContent.key}}}) - LENGTH(REPLACE({{${postContent.key}}}, " ", "")) + 1`,
        dependencies: [postContent.key],
        recalculateOnUpdate: true,
      }),
    ],
  })

  postEntity.addProperty({
    info: { name: 'meta_title', displayName: 'Meta Title', description: 'SEO meta title' },
    type: 'string',
    // semantics: [{ id: SemanticType.SEOTitle }],
  })

  postEntity.addProperty({
    info: { name: 'meta_description', displayName: 'Meta Description', description: 'SEO meta description' },
    type: 'string',
    // semantics: [{ id: SemanticType.SEODescription }],
  })

  addCreatedAtField(postEntity, { description: 'When the post was created' })
  addUpdatedAtField(postEntity, { description: 'When the post was last updated' })

  // Post-Publication Association (Many-to-One)
  postEntity.addAssociation(
    { key: publicationEntity.key },
    {
      info: { name: 'publication', displayName: 'Publication', description: 'Publication this post belongs to' },
      required: true,
      multiple: false,
    }
  )

  // Post-Category Association (Many-to-Many)
  postEntity.addAssociation(
    { key: categoryEntity.key },
    {
      info: { name: 'categories', displayName: 'Post Categories', description: 'Categories this post belongs to' },
      required: false,
      multiple: true,
      semantics: [{ id: SemanticType.Categories }],
    }
  )

  // Post-Tag Association (Many-to-Many)
  postEntity.addAssociation(
    { key: tagEntity.key },
    {
      info: { name: 'tags', displayName: 'Post Tags', description: 'Tags associated with this post' },
      required: false,
      multiple: true,
      semantics: [{ id: SemanticType.Tags }],
    }
  )

  //
  // 2. USER MANAGEMENT NAMESPACE
  //
  const userManagement = domain.addNamespace({
    info: {
      name: 'UserManagement',
      displayName: 'User Management',
      description: 'Authors, editors, subscribers, and user roles management',
    },
  })

  // User Model
  const userModel = userManagement.addModel({
    info: {
      name: 'Users',
      displayName: 'User Management',
      description: 'User accounts and authentication',
    },
  })

  // User Entity
  const userEntity = userModel.addEntity({
    info: {
      name: 'user',
      displayName: 'User Account',
      description: 'User account for authors, editors, and subscribers',
    },
    semantics: [{ id: SemanticType.User }],
  })

  addIdField(userEntity, { displayName: 'User ID', description: 'Unique identifier for the user' })

  addEmailField(userEntity, { description: 'User email address for login and communication' })

  addPasswordField(userEntity, { description: 'Encrypted password for authentication' })

  userEntity.addProperty({
    info: { name: 'username', displayName: 'Username', description: 'Unique username for the user' },
    type: 'string',
    required: true,
    unique: true,
    semantics: [{ id: SemanticType.PublicUniqueName }],
  })

  userEntity.addProperty({
    info: { name: 'display_name', displayName: 'Display Name', description: 'Public display name for the user' },
    type: 'string',
    required: true,
  })

  addFirstNameField(userEntity, { description: 'User first name' })
  addLastNameField(userEntity, { description: 'User last name' })

  userEntity.addProperty({
    info: { name: 'bio', displayName: 'Biography', description: 'User biography and description' },
    type: 'string',
    semantics: [{ id: SemanticType.Description }],
  })

  addAvatarUrlField(userEntity, { description: 'URL to user profile picture' })

  userEntity.addProperty({
    info: { name: 'website', displayName: 'Website', description: 'User personal website URL' },
    type: 'string',
    semantics: [createURLSemantic()],
  })

  // userEntity.addProperty({
  //   info: {
  //     name: 'social_links',
  //     displayName: 'Social Links',
  //     description: 'JSON object containing social media links',
  //   },
  //   type: 'string',
  //   // semantics: [{ id: SemanticType.SocialMediaLinks }],
  // })

  userEntity.addProperty({
    info: { name: 'role', displayName: 'User Role', description: 'User role for permission management' },
    type: 'string',
    required: true,
    schema: {
      enum: ['subscriber', 'author', 'editor', 'admin', 'super_admin'],
      defaultValue: {
        type: 'literal',
        value: 'subscriber',
      },
    },
    semantics: [{ id: SemanticType.UserRole }],
  })

  addCustomStatusField(userEntity, ['active', 'inactive', 'suspended', 'pending_verification'], {
    displayName: 'User Status',
    description: 'Current status of the user account',
  })

  addBooleanField(userEntity, 'emailVerified', 'false', {
    displayName: 'Email Verified',
    description: 'Whether the user has verified their email',
  })

  // userEntity.addProperty({
  //   info: { name: 'last_login_at', displayName: 'Last Login At', description: 'When the user last logged in' },
  //   type: 'datetime',
  //   readOnly: true,
  //   semantics: [{ id: SemanticType.LastLoginTimestamp }],
  // })

  addCreatedAtField(userEntity, { description: 'When the user account was created' })

  // Post-Author Association (Many-to-One)
  postEntity.addAssociation(
    { key: userEntity.key },
    {
      info: { name: 'author', displayName: 'Post Author', description: 'Author who wrote this post' },
      required: true,
      multiple: false,
      semantics: [{ id: SemanticType.ResourceOwnerIdentifier }],
    }
  )

  //
  // 3. SOCIAL FEATURES NAMESPACE
  //
  const socialFeatures = domain.addNamespace({
    info: {
      name: 'SocialFeatures',
      displayName: 'Social Features',
      description: 'Comments, likes, shares, and social interactions',
    },
  })

  // Comment Model
  const commentModel = socialFeatures.addModel({
    info: {
      name: 'Comments',
      displayName: 'Comment System',
      description: 'Post comments and replies',
    },
  })

  // Comment Entity
  const commentEntity = commentModel.addEntity({
    info: {
      name: 'comment',
      displayName: 'Comment',
      description: 'User comments on posts',
    },
  })

  addIdField(commentEntity, { displayName: 'Comment ID', description: 'Unique identifier for the comment' })

  commentEntity.addProperty({
    info: { name: 'content', displayName: 'Comment Content', description: 'Content of the comment' },
    type: 'string',
    required: true,
  })

  commentEntity.addProperty({
    info: {
      name: 'author_name',
      displayName: 'Author Name',
      description: 'Name of the comment author (for guest comments)',
    },
    type: 'string',
  })

  addEmailField(commentEntity, {
    name: 'author_email',
    displayName: 'Author Email',
    description: 'Email of the comment author (for guest comments)',
  })

  addCustomStatusField(commentEntity, ['pending', 'approved', 'rejected', 'spam'], {
    displayName: 'Comment Status',
    description: 'Moderation status of the comment',
  })

  // commentEntity.addProperty({
  //   info: { name: 'ip_address', displayName: 'IP Address', description: 'IP address of the commenter' },
  //   type: 'string',
  //   semantics: [{ id: SemanticType.IPAddress }],
  // })

  commentEntity.addProperty({
    info: { name: 'user_agent', displayName: 'User Agent', description: 'Browser user agent string' },
    type: 'string',
  })

  addCreatedAtField(commentEntity, { description: 'When the comment was created' })

  // Comment-Post Association (Many-to-One)
  commentEntity.addAssociation(
    { key: postEntity.key },
    {
      info: { name: 'post', displayName: 'Post', description: 'Post this comment belongs to' },
      required: true,
      multiple: false,
    }
  )

  // Comment-User Association (Many-to-One) - Optional for guest comments
  commentEntity.addAssociation(
    { key: userEntity.key },
    {
      info: { name: 'author', displayName: 'Comment Author', description: 'Registered user who wrote this comment' },
      required: false,
      multiple: false,
      semantics: [{ id: SemanticType.ResourceOwnerIdentifier }],
    }
  )

  // Self-referencing association for comment replies
  commentEntity.addAssociation(
    { key: commentEntity.key },
    {
      info: { name: 'parent_comment', displayName: 'Parent Comment', description: 'Parent comment for replies' },
      required: false,
      multiple: false,
    }
  )

  //
  // 4. ANALYTICS NAMESPACE
  //
  const analytics = domain.addNamespace({
    info: {
      name: 'Analytics',
      displayName: 'Analytics & Tracking',
      description: 'Analytics, metrics, and performance tracking',
    },
  })

  // Analytics Model
  const analyticsModel = analytics.addModel({
    info: {
      name: 'Analytics',
      displayName: 'Content Analytics',
      description: 'Content performance and user engagement metrics',
    },
  })

  // Page View Entity
  const pageViewEntity = analyticsModel.addEntity({
    info: {
      name: 'page_view',
      displayName: 'Page View',
      description: 'Individual page view tracking record',
    },
  })

  addIdField(pageViewEntity, { displayName: 'Page View ID', description: 'Unique identifier for the page view' })

  pageViewEntity.addProperty({
    info: { name: 'path', displayName: 'Page Path', description: 'URL path of the viewed page' },
    type: 'string',
    required: true,
  })

  pageViewEntity.addProperty({
    info: { name: 'referrer', displayName: 'Referrer', description: 'Referring URL' },
    type: 'string',
    semantics: [createURLSemantic()],
  })

  pageViewEntity.addProperty({
    info: { name: 'ip_address', displayName: 'IP Address', description: 'Visitor IP address' },
    type: 'string',
    semantics: [{ id: SemanticType.ClientIPAddress }],
  })

  pageViewEntity.addProperty({
    info: { name: 'user_agent', displayName: 'User Agent', description: 'Browser user agent string' },
    type: 'string',
  })

  pageViewEntity.addProperty({
    info: { name: 'session_id', displayName: 'Session ID', description: 'Visitor session identifier' },
    type: 'string',
  })

  addCreatedAtField(pageViewEntity, {
    name: 'viewed_at',
    displayName: 'Viewed At',
    description: 'When the page was viewed',
  })

  // PageView-Post Association (Many-to-One) - Optional, only for post views
  pageViewEntity.addAssociation(
    { key: postEntity.key },
    {
      info: { name: 'post', displayName: 'Viewed Post', description: 'Post that was viewed (if applicable)' },
      required: false,
      multiple: false,
    }
  )

  // PageView-Publication Association (Many-to-One)
  pageViewEntity.addAssociation(
    { key: publicationEntity.key },
    {
      info: { name: 'publication', displayName: 'Publication', description: 'Publication this page view belongs to' },
      required: true,
      multiple: false,
    }
  )

  //
  // 5. MEDIA MANAGEMENT NAMESPACE
  //
  const mediaManagement = domain.addNamespace({
    info: {
      name: 'MediaManagement',
      displayName: 'Media Management',
      description: 'Image, video, and file upload management',
    },
  })

  // Media Model
  const mediaModel = mediaManagement.addModel({
    info: {
      name: 'Media',
      displayName: 'Media Library',
      description: 'Uploaded files, images, and media assets',
    },
  })

  // Media File Entity
  const mediaFileEntity = mediaModel.addEntity({
    info: {
      name: 'media_file',
      displayName: 'Media File',
      description: 'Uploaded media files (images, videos, documents)',
    },
  })

  addIdField(mediaFileEntity, { displayName: 'Media File ID', description: 'Unique identifier for the media file' })

  mediaFileEntity.addProperty({
    info: { name: 'filename', displayName: 'File Name', description: 'Original filename of the uploaded file' },
    type: 'string',
    required: true,
  })

  mediaFileEntity.addProperty({
    info: { name: 'storage_key', displayName: 'Storage Key', description: 'Unique storage key for the file' },
    type: 'string',
    required: true,
    unique: true,
  })

  mediaFileEntity.addProperty({
    info: { name: 'url', displayName: 'File URL', description: 'Public URL to access the file' },
    type: 'string',
    required: true,
    semantics: [createURLSemantic()],
  })

  mediaFileEntity.addProperty({
    info: { name: 'mime_type', displayName: 'MIME Type', description: 'MIME type of the file' },
    type: 'string',
    required: true,
  })

  addQuantityField(mediaFileEntity, {
    name: 'file_size',
    displayName: 'File Size',
    description: 'File size in bytes',
  })

  addQuantityField(mediaFileEntity, {
    name: 'width',
    displayName: 'Image Width',
    description: 'Width in pixels (for images)',
  })

  addQuantityField(mediaFileEntity, {
    name: 'height',
    displayName: 'Image Height',
    description: 'Height in pixels (for images)',
  })

  mediaFileEntity.addProperty({
    info: { name: 'alt_text', displayName: 'Alt Text', description: 'Alternative text for accessibility' },
    type: 'string',
    // semantics: [{ id: SemanticType.ImageAltText }],
  })

  addCreatedAtField(mediaFileEntity, {
    name: 'uploaded_at',
    displayName: 'Uploaded At',
    description: 'When the file was uploaded',
  })

  // MediaFile-User Association (Many-to-One)
  mediaFileEntity.addAssociation(
    { key: userEntity.key },
    {
      info: { name: 'uploader', displayName: 'File Uploader', description: 'User who uploaded this file' },
      required: true,
      multiple: false,
      semantics: [{ id: SemanticType.ResourceOwnerIdentifier }],
    }
  )

  // MediaFile-Publication Association (Many-to-One)
  mediaFileEntity.addAssociation(
    { key: publicationEntity.key },
    {
      info: { name: 'publication', displayName: 'Publication', description: 'Publication this media file belongs to' },
      required: true,
      multiple: false,
    }
  )

  return domain
}
