import {
  pgTable,
  uuid,
  varchar,
  text,
  integer,
  jsonb,
  timestamp,
  pgEnum,
  index,
  uniqueIndex,
  check,
  type AnyPgColumn,
} from 'drizzle-orm/pg-core';
import { sql } from 'drizzle-orm';
import { projects } from './projects';
import { flows } from './flows';
import { apiKeys } from './apiKeys';

// Enum for image source
export const imageSourceEnum = pgEnum('image_source', ['generated', 'uploaded']);

// Type for focal point JSONB
export type FocalPoint = {
  x: number; // 0.0 - 1.0
  y: number; // 0.0 - 1.0
};

export const images = pgTable(
  'images',
  {
    id: uuid('id').primaryKey().defaultRandom(),

    // Relations
    projectId: uuid('project_id')
      .notNull()
      .references(() => projects.id, { onDelete: 'cascade' }),
    generationId: uuid('generation_id').references(
      (): AnyPgColumn => {
        const { generations } = require('./generations');
        return generations.id;
      },
      { onDelete: 'set null' },
    ),
    flowId: uuid('flow_id').references(() => flows.id, { onDelete: 'cascade' }),
    pendingFlowId: text('pending_flow_id'), // Temporary UUID for lazy flow pattern
    apiKeyId: uuid('api_key_id').references(() => apiKeys.id, { onDelete: 'set null' }),

    // Storage (MinIO path format: orgSlug/projectSlug/img/{imageId})
    // Note: imageId = this record's UUID, filename has no extension
    storageKey: varchar('storage_key', { length: 500 }).notNull().unique(),
    storageUrl: text('storage_url').notNull(),

    // File metadata
    mimeType: varchar('mime_type', { length: 100 }).notNull(),
    fileSize: integer('file_size').notNull(),
    fileHash: varchar('file_hash', { length: 64 }), // SHA-256 for deduplication
    originalFilename: varchar('original_filename', { length: 255 }), // User's original filename
    fileExtension: varchar('file_extension', { length: 20 }), // Original extension (png, jpg, etc.)

    // Dimensions
    width: integer('width'),
    height: integer('height'),
    aspectRatio: varchar('aspect_ratio', { length: 10 }),

    // Focal point for image transformations (imageflow)
    // Normalized coordinates: { "x": 0.5, "y": 0.3 } where 0.0-1.0
    focalPoint: jsonb('focal_point').$type<FocalPoint>(),

    // Source
    source: imageSourceEnum('source').notNull(),

    // Project-level alias (global scope)
    // Flow-level aliases stored in flows.aliases
    alias: varchar('alias', { length: 100 }),

    // Metadata
    description: text('description'),
    tags: text('tags').array(),
    meta: jsonb('meta').$type<Record<string, unknown>>().notNull().default({}),

    // Audit
    createdAt: timestamp('created_at').notNull().defaultNow(),
    updatedAt: timestamp('updated_at')
      .notNull()
      .defaultNow()
      .$onUpdate(() => new Date()),
    deletedAt: timestamp('deleted_at'), // Soft delete
  },
  (table) => ({
    // CHECK constraints
    sourceGeneratedCheck: check(
      'source_generation_check',
      sql`(${table.source} = 'uploaded' AND ${table.generationId} IS NULL) OR (${table.source} = 'generated' AND ${table.generationId} IS NOT NULL)`,
    ),
    aliasFormatCheck: check(
      'alias_format_check',
      sql`${table.alias} IS NULL OR ${table.alias} ~ '^@[a-zA-Z0-9_-]+$'`,
    ),
    fileSizeCheck: check('file_size_check', sql`${table.fileSize} > 0`),
    widthCheck: check(
      'width_check',
      sql`${table.width} IS NULL OR (${table.width} > 0 AND ${table.width} <= 8192)`,
    ),
    heightCheck: check(
      'height_check',
      sql`${table.height} IS NULL OR (${table.height} > 0 AND ${table.height} <= 8192)`,
    ),

    // Indexes
    // Unique index for project-scoped aliases (partial index)
    projectAliasIdx: uniqueIndex('idx_images_project_alias')
      .on(table.projectId, table.alias)
      .where(sql`${table.alias} IS NOT NULL AND ${table.deletedAt} IS NULL AND ${table.flowId} IS NULL`),

    // Index for querying images by project and source (partial index)
    projectSourceIdx: index('idx_images_project_source')
      .on(table.projectId, table.source, table.createdAt.desc())
      .where(sql`${table.deletedAt} IS NULL`),

    // Index for flow-scoped images (partial index)
    flowIdx: index('idx_images_flow')
      .on(table.flowId)
      .where(sql`${table.flowId} IS NOT NULL`),

    // Index for pending flow lookups (lazy pattern)
    pendingFlowIdx: index('idx_images_pending_flow')
      .on(table.pendingFlowId, table.createdAt.desc())
      .where(sql`${table.pendingFlowId} IS NOT NULL`),

    // Index for generation lookup
    generationIdx: index('idx_images_generation').on(table.generationId),

    // Index for storage key lookup
    storageKeyIdx: index('idx_images_storage_key').on(table.storageKey),

    // Index for file hash (deduplication)
    hashIdx: index('idx_images_hash').on(table.fileHash),

    // Index for API key audit trail
    apiKeyIdx: index('idx_images_api_key').on(table.apiKeyId),
  }),
);

export type Image = typeof images.$inferSelect;
export type NewImage = typeof images.$inferInsert;
