import {
  bigint as pgBigint,
  foreignKey as pgForeignKey,
  index as pgIndex,
  integer as pgInteger,
  real as pgReal,
  pgTable,
  text as pgText,
} from "drizzle-orm/pg-core";
import {
  index as sqliteIndex,
  integer as sqliteInteger,
  real as sqliteReal,
  sqliteTable,
  text as sqliteText,
} from "drizzle-orm/sqlite-core";
import { config } from "../config.js";

// PostgreSQL Schema
// ==================

/**
 * Muxer Jobs Table (PostgreSQL)
 * Tracks audio post-processing jobs with status and retry logic
 */
export const pgMuxerJobsTable = pgTable(
  "muxer_jobs",
  {
    id: pgText("id").primaryKey(),
    data: pgText("data").notNull(),
    status: pgText("status", {
      enum: ["pending", "processing", "completed", "failed"],
    })
      .notNull()
      .default("pending"),
    attempts: pgInteger("attempts").notNull().default(0),
    maxAttempts: pgInteger("maxAttempts").notNull().default(3),
    createdAt: pgBigint("createdAt", { mode: "number" }).notNull(),
    updatedAt: pgBigint("updatedAt", { mode: "number" }).notNull(),
    error: pgText("error"),
  },
  (table) => ({
    statusIdx: pgIndex("idx_muxer_jobs_status").on(table.status),
    createdAtIdx: pgIndex("idx_muxer_jobs_createdAt").on(table.createdAt),
  }),
);

/**
 * Messages Table (PostgreSQL)
 * Stores text messages with AI moderation analysis
 */
export const pgMessagesTable = pgTable(
  "messages",
  {
    id: pgText("id").primaryKey(),
    guild_id: pgText("guild_id").notNull(),
    channel_id: pgText("channel_id").notNull(),
    thread_id: pgText("thread_id"),
    user_id: pgText("user_id").notNull(),
    username: pgText("username").notNull(),
    avatar_url: pgText("avatar_url"),
    content: pgText("content").notNull(),
    edited_content: pgText("edited_content"),
    created_at: pgBigint("created_at", { mode: "number" }).notNull(),
    edited_at: pgBigint("edited_at", { mode: "number" }),
    deleted_at: pgBigint("deleted_at", { mode: "number" }),
    type: pgText("type", { enum: ["text", "edited", "deleted"] })
      .notNull()
      .default("text"),
    metadata: pgText("metadata"),
    ai_status: pgText("ai_status", {
      enum: ["pending", "clean", "warn", "flagged", "error"],
    })
      .notNull()
      .default("pending"),
    ai_moderation_flags: pgText("ai_moderation_flags"),
    ai_moderation_score: pgReal("ai_moderation_score"),
    ai_moderation_raw: pgText("ai_moderation_raw"),
    ai_analysis: pgText("ai_analysis"),
    ai_analyzed_at: pgBigint("ai_analyzed_at", { mode: "number" }),
    ai_error: pgText("ai_error"),
  },
  (table) => ({
    channelIdx: pgIndex("idx_messages_channel").on(table.channel_id),
    userIdx: pgIndex("idx_messages_user").on(table.user_id),
    createdIdx: pgIndex("idx_messages_created").on(table.created_at),
    threadIdx: pgIndex("idx_messages_thread").on(table.thread_id),
    channelCreatedIdx: pgIndex("idx_messages_channel_created").on(
      table.channel_id,
      table.created_at,
      table.id,
    ),
    threadCreatedIdx: pgIndex("idx_messages_thread_created").on(
      table.thread_id,
      table.created_at,
      table.id,
    ),
    aiStatusCreatedIdx: pgIndex("idx_messages_ai_status_created").on(
      table.ai_status,
      table.created_at,
      table.id,
    ),
    guildAiStatusCreatedIdx: pgIndex("idx_messages_guild_ai_status_created").on(
      table.guild_id,
      table.ai_status,
      table.created_at,
      table.id,
    ),
  }),
);

/**
 * Attachments Table (PostgreSQL)
 * Stores attachment metadata with upload status tracking
 */
export const pgAttachmentsTable = pgTable(
  "attachments",
  {
    id: pgText("id").primaryKey(),
    message_id: pgText("message_id").notNull(),
    guild_id: pgText("guild_id").notNull(),
    channel_id: pgText("channel_id").notNull(),
    thread_id: pgText("thread_id"),
    user_id: pgText("user_id").notNull(),
    filename: pgText("filename").notNull(),
    size: pgInteger("size").notNull(),
    type: pgText("type").notNull(),
    discord_url: pgText("discord_url").notNull(),
    uploaded_url: pgText("uploaded_url"),
    upload_status: pgText("upload_status", {
      enum: ["pending", "uploaded", "failed"],
    })
      .notNull()
      .default("pending"),
    upload_error: pgText("upload_error"),
    created_at: pgBigint("created_at", { mode: "number" }).notNull(),
    uploaded_at: pgBigint("uploaded_at", { mode: "number" }),
  },
  (table) => ({
    channelIdx: pgIndex("idx_attachments_channel").on(table.channel_id),
    messageIdx: pgIndex("idx_attachments_message").on(table.message_id),
    statusIdx: pgIndex("idx_attachments_status").on(table.upload_status),
    channelCreatedIdx: pgIndex("idx_attachments_channel_created").on(
      table.channel_id,
      table.created_at,
      table.id,
    ),
    threadCreatedIdx: pgIndex("idx_attachments_thread_created").on(
      table.thread_id,
      table.created_at,
      table.id,
    ),
    messageFk: pgForeignKey({
      columns: [table.message_id],
      foreignColumns: [pgMessagesTable.id],
      name: "fk_attachments_message_id",
    }).onDelete("cascade"),
  }),
);

/**
 * UI State Table (PostgreSQL)
 * Stores persistent UI state (e.g., selected channel, filter preferences)
 */
export const pgUIStateTable = pgTable("ui_state", {
  key: pgText("key").primaryKey(),
  value: pgText("value").notNull(),
  updated_at: pgBigint("updated_at", { mode: "number" }).notNull(),
});

/**
 * AI Analysis Runs Table (PostgreSQL)
 * Tracks AI analysis batch runs for conversation-level moderation
 */
export const pgAIAnalysisRunsTable = pgTable(
  "ai_analysis_runs",
  {
    id: pgText("id").primaryKey(),
    conversation_key: pgText("conversation_key").notNull(),
    target_message_ids: pgText("target_message_ids").notNull(), // JSON array
    model: pgText("model").notNull(),
    request_tokens_estimate: pgInteger("request_tokens_estimate"),
    response_raw: pgText("response_raw"),
    status: pgText("status", {
      enum: ["pending", "processing", "completed", "failed"],
    })
      .notNull()
      .default("pending"),
    error: pgText("error"),
    created_at: pgBigint("created_at", { mode: "number" }).notNull(),
    completed_at: pgBigint("completed_at", { mode: "number" }),
  },
  (table) => ({
    conversationKeyIdx: pgIndex("idx_ai_analysis_runs_conversation_key").on(
      table.conversation_key,
    ),
    statusIdx: pgIndex("idx_ai_analysis_runs_status").on(table.status),
    createdAtIdx: pgIndex("idx_ai_analysis_runs_created_at").on(
      table.created_at,
    ),
  }),
);

/**
 * Voice Recordings Table (PostgreSQL)
 * Stores voice recording segment metadata and upload status
 */
export const pgVoiceRecordingsTable = pgTable(
  "voice_recordings",
  {
    id: pgText("id").primaryKey(),
    user_id: pgText("user_id").notNull(),
    username: pgText("username").notNull(),
    avatar_url: pgText("avatar_url"),
    guild_id: pgText("guild_id"),
    channel_id: pgText("channel_id"),
    channel_name: pgText("channel_name"),
    filename: pgText("filename").notNull(),
    size_bytes: pgInteger("size_bytes").notNull(),
    download_url: pgText("download_url"),
    upload_status: pgText("upload_status", {
      enum: ["pending", "uploaded", "failed"],
    })
      .notNull()
      .default("pending"),
    upload_error: pgText("upload_error"),
    created_at: pgBigint("created_at", { mode: "number" }).notNull(),
    uploaded_at: pgBigint("uploaded_at", { mode: "number" }),
  },
  (table) => ({
    userIdIdx: pgIndex("idx_voice_recordings_user_id").on(table.user_id),
    channelIdIdx: pgIndex("idx_voice_recordings_channel_id").on(
      table.channel_id,
    ),
    createdIdx: pgIndex("idx_voice_recordings_created_at").on(table.created_at),
  }),
);

// SQLite Schema
// =============

/**
 * Muxer Jobs Table (SQLite)
 * Tracks audio post-processing jobs with status and retry logic
 */
export const sqliteMuxerJobsTable = sqliteTable(
  "muxer_jobs",
  {
    id: sqliteText("id").primaryKey(),
    data: sqliteText("data").notNull(),
    status: sqliteText("status", {
      enum: ["pending", "processing", "completed", "failed"],
    })
      .notNull()
      .default("pending"),
    attempts: sqliteInteger("attempts").notNull().default(0),
    maxAttempts: sqliteInteger("maxAttempts").notNull().default(3),
    createdAt: sqliteInteger("createdAt").notNull(),
    updatedAt: sqliteInteger("updatedAt").notNull(),
    error: sqliteText("error"),
  },
  (table) => ({
    statusIdx: sqliteIndex("idx_muxer_jobs_status").on(table.status),
    createdAtIdx: sqliteIndex("idx_muxer_jobs_createdAt").on(table.createdAt),
  }),
);

/**
 * Messages Table (SQLite)
 * Stores text messages with AI moderation analysis
 */
export const sqliteMessagesTable = sqliteTable(
  "messages",
  {
    id: sqliteText("id").primaryKey(),
    guild_id: sqliteText("guild_id").notNull(),
    channel_id: sqliteText("channel_id").notNull(),
    thread_id: sqliteText("thread_id"),
    user_id: sqliteText("user_id").notNull(),
    username: sqliteText("username").notNull(),
    avatar_url: sqliteText("avatar_url"),
    content: sqliteText("content").notNull(),
    edited_content: sqliteText("edited_content"),
    created_at: sqliteInteger("created_at").notNull(),
    edited_at: sqliteInteger("edited_at"),
    deleted_at: sqliteInteger("deleted_at"),
    type: sqliteText("type", { enum: ["text", "edited", "deleted"] })
      .notNull()
      .default("text"),
    metadata: sqliteText("metadata"),
    ai_status: sqliteText("ai_status", {
      enum: ["pending", "clean", "warn", "flagged", "error"],
    })
      .notNull()
      .default("pending"),
    ai_moderation_flags: sqliteText("ai_moderation_flags"),
    ai_moderation_score: sqliteReal("ai_moderation_score"),
    ai_moderation_raw: sqliteText("ai_moderation_raw"),
    ai_analysis: sqliteText("ai_analysis"),
    ai_analyzed_at: sqliteInteger("ai_analyzed_at"),
    ai_error: sqliteText("ai_error"),
  },
  (table) => ({
    channelIdx: sqliteIndex("idx_messages_channel").on(table.channel_id),
    userIdx: sqliteIndex("idx_messages_user").on(table.user_id),
    createdIdx: sqliteIndex("idx_messages_created").on(table.created_at),
    threadIdx: sqliteIndex("idx_messages_thread").on(table.thread_id),
    channelCreatedIdx: sqliteIndex("idx_messages_channel_created").on(
      table.channel_id,
      table.created_at,
      table.id,
    ),
    threadCreatedIdx: sqliteIndex("idx_messages_thread_created").on(
      table.thread_id,
      table.created_at,
      table.id,
    ),
    aiStatusCreatedIdx: sqliteIndex("idx_messages_ai_status_created").on(
      table.ai_status,
      table.created_at,
      table.id,
    ),
    guildAiStatusCreatedIdx: sqliteIndex(
      "idx_messages_guild_ai_status_created",
    ).on(table.guild_id, table.ai_status, table.created_at, table.id),
  }),
);

/**
 * Attachments Table (SQLite)
 * Stores attachment metadata with upload status tracking
 */
export const sqliteAttachmentsTable = sqliteTable(
  "attachments",
  {
    id: sqliteText("id").primaryKey(),
    message_id: sqliteText("message_id").notNull(),
    guild_id: sqliteText("guild_id").notNull(),
    channel_id: sqliteText("channel_id").notNull(),
    thread_id: sqliteText("thread_id"),
    user_id: sqliteText("user_id").notNull(),
    filename: sqliteText("filename").notNull(),
    size: sqliteInteger("size").notNull(),
    type: sqliteText("type").notNull(),
    discord_url: sqliteText("discord_url").notNull(),
    uploaded_url: sqliteText("uploaded_url"),
    upload_status: sqliteText("upload_status", {
      enum: ["pending", "uploaded", "failed"],
    })
      .notNull()
      .default("pending"),
    upload_error: sqliteText("upload_error"),
    created_at: sqliteInteger("created_at").notNull(),
    uploaded_at: sqliteInteger("uploaded_at"),
  },
  (table) => ({
    channelIdx: sqliteIndex("idx_attachments_channel").on(table.channel_id),
    messageIdx: sqliteIndex("idx_attachments_message").on(table.message_id),
    statusIdx: sqliteIndex("idx_attachments_status").on(table.upload_status),
    channelCreatedIdx: sqliteIndex("idx_attachments_channel_created").on(
      table.channel_id,
      table.created_at,
      table.id,
    ),
    threadCreatedIdx: sqliteIndex("idx_attachments_thread_created").on(
      table.thread_id,
      table.created_at,
      table.id,
    ),
  }),
);

/**
 * UI State Table (SQLite)
 * Stores persistent UI state (e.g., selected channel, filter preferences)
 */
export const sqliteUIStateTable = sqliteTable("ui_state", {
  key: sqliteText("key").primaryKey(),
  value: sqliteText("value").notNull(),
  updated_at: sqliteInteger("updated_at").notNull(),
});

/**
 * AI Analysis Runs Table (SQLite)
 * Tracks AI analysis batch runs for conversation-level moderation
 */
export const sqliteAIAnalysisRunsTable = sqliteTable(
  "ai_analysis_runs",
  {
    id: sqliteText("id").primaryKey(),
    conversation_key: sqliteText("conversation_key").notNull(),
    target_message_ids: sqliteText("target_message_ids").notNull(), // JSON array
    model: sqliteText("model").notNull(),
    request_tokens_estimate: sqliteInteger("request_tokens_estimate"),
    response_raw: sqliteText("response_raw"),
    status: sqliteText("status", {
      enum: ["pending", "processing", "completed", "failed"],
    })
      .notNull()
      .default("pending"),
    error: sqliteText("error"),
    created_at: sqliteInteger("created_at").notNull(),
    completed_at: sqliteInteger("completed_at"),
  },
  (table) => ({
    conversationKeyIdx: sqliteIndex("idx_ai_analysis_runs_conversation_key").on(
      table.conversation_key,
    ),
    statusIdx: sqliteIndex("idx_ai_analysis_runs_status").on(table.status),
    createdAtIdx: sqliteIndex("idx_ai_analysis_runs_created_at").on(
      table.created_at,
    ),
  }),
);

/**
 * Voice Recordings Table (SQLite)
 * Stores voice recording segment metadata and upload status
 */
export const sqliteVoiceRecordingsTable = sqliteTable(
  "voice_recordings",
  {
    id: sqliteText("id").primaryKey(),
    user_id: sqliteText("user_id").notNull(),
    username: sqliteText("username").notNull(),
    avatar_url: sqliteText("avatar_url"),
    guild_id: sqliteText("guild_id"),
    channel_id: sqliteText("channel_id"),
    channel_name: sqliteText("channel_name"),
    filename: sqliteText("filename").notNull(),
    size_bytes: sqliteInteger("size_bytes").notNull(),
    download_url: sqliteText("download_url"),
    upload_status: sqliteText("upload_status", {
      enum: ["pending", "uploaded", "failed"],
    })
      .notNull()
      .default("pending"),
    upload_error: sqliteText("upload_error"),
    created_at: sqliteInteger("created_at").notNull(),
    uploaded_at: sqliteInteger("uploaded_at"),
  },
  (table) => ({
    userIdIdx: sqliteIndex("idx_voice_recordings_user_id").on(table.user_id),
    channelIdIdx: sqliteIndex("idx_voice_recordings_channel_id").on(
      table.channel_id,
    ),
    createdIdx: sqliteIndex("idx_voice_recordings_created_at").on(
      table.created_at,
    ),
  }),
);

// Runtime table selection based on config
// ========================================

export const muxerJobsTable =
  config.DATABASE_TYPE === "postgres" ? pgMuxerJobsTable : sqliteMuxerJobsTable;

export const messagesTable =
  config.DATABASE_TYPE === "postgres" ? pgMessagesTable : sqliteMessagesTable;

export const attachmentsTable =
  config.DATABASE_TYPE === "postgres"
    ? pgAttachmentsTable
    : sqliteAttachmentsTable;

export const uiStateTable =
  config.DATABASE_TYPE === "postgres" ? pgUIStateTable : sqliteUIStateTable;

export const aiAnalysisRunsTable =
  config.DATABASE_TYPE === "postgres"
    ? pgAIAnalysisRunsTable
    : sqliteAIAnalysisRunsTable;

export const voiceRecordingsTable =
  config.DATABASE_TYPE === "postgres"
    ? pgVoiceRecordingsTable
    : sqliteVoiceRecordingsTable;

// Export table types for use in queries
export type MuxerJob = typeof muxerJobsTable.$inferSelect;
export type MuxerJobInsert = typeof muxerJobsTable.$inferInsert;

export type Message = typeof messagesTable.$inferSelect;
export type MessageInsert = typeof messagesTable.$inferInsert;

export type Attachment = typeof attachmentsTable.$inferSelect;
export type AttachmentInsert = typeof attachmentsTable.$inferInsert;

export type UIState = typeof uiStateTable.$inferSelect;
export type UIStateInsert = typeof uiStateTable.$inferInsert;

export type AIAnalysisRun = typeof aiAnalysisRunsTable.$inferSelect;
export type AIAnalysisRunInsert = typeof aiAnalysisRunsTable.$inferInsert;

export type VoiceRecording = typeof voiceRecordingsTable.$inferSelect;
export type VoiceRecordingInsert = typeof voiceRecordingsTable.$inferInsert;
