import {
    bigint,
    boolean,
    index,
    integer,
    jsonb,
    pgTable,
    text,
    timestamp,
    uniqueIndex,
    uuid,
} from "drizzle-orm/pg-core"

import { tenants } from "./tenants"
import { authUsers } from "./auth_users"
import { userCredentials } from "./user_credentials"

export const emailMailboxes = pgTable(
    "email_mailboxes",
    {
        id: uuid("id").primaryKey().defaultRandom(),

        tenantId: bigint("tenant_id", { mode: "number" })
            .notNull()
            .references(() => tenants.id, { onDelete: "cascade", onUpdate: "cascade" }),

        userId: uuid("user_id")
            .notNull()
            .references(() => authUsers.id, { onDelete: "cascade", onUpdate: "cascade" }),

        accountId: uuid("account_id")
            .notNull()
            .references(() => userCredentials.id, { onDelete: "cascade", onUpdate: "cascade" }),

        path: text("path").notNull(),
        delimiter: text("delimiter"),
        name: text("name").notNull(),
        specialUse: text("special_use"),
        flags: jsonb("flags").$type<string[]>(),
        exists: integer("exists").notNull().default(0),
        unseen: integer("unseen").notNull().default(0),

        createdAt: timestamp("created_at", { withTimezone: true })
            .notNull()
            .defaultNow(),
        updatedAt: timestamp("updated_at", { withTimezone: true }),
    },
    (table) => ({
        accountPathKey: uniqueIndex("email_mailboxes_account_path_key")
            .on(table.accountId, table.path),
        tenantAccountIdx: index("email_mailboxes_tenant_account_idx")
            .on(table.tenantId, table.accountId),
    }),
)

export const emailMessages = pgTable(
    "email_messages",
    {
        id: uuid("id").primaryKey().defaultRandom(),

        tenantId: bigint("tenant_id", { mode: "number" })
            .notNull()
            .references(() => tenants.id, { onDelete: "cascade", onUpdate: "cascade" }),

        userId: uuid("user_id")
            .notNull()
            .references(() => authUsers.id, { onDelete: "cascade", onUpdate: "cascade" }),

        accountId: uuid("account_id")
            .notNull()
            .references(() => userCredentials.id, { onDelete: "cascade", onUpdate: "cascade" }),

        mailboxId: uuid("mailbox_id")
            .notNull()
            .references(() => emailMailboxes.id, { onDelete: "cascade", onUpdate: "cascade" }),

        mailboxPath: text("mailbox_path").notNull(),
        uid: bigint("uid", { mode: "number" }).notNull(),
        emailId: text("email_id"),
        messageId: text("message_id"),
        inReplyTo: text("in_reply_to"),
        threadId: text("thread_id"),
        subject: text("subject"),
        from: jsonb("from").$type<Array<{ name?: string | null; address?: string | null }>>(),
        to: jsonb("to").$type<Array<{ name?: string | null; address?: string | null }>>(),
        cc: jsonb("cc").$type<Array<{ name?: string | null; address?: string | null }>>(),
        bcc: jsonb("bcc").$type<Array<{ name?: string | null; address?: string | null }>>(),
        replyTo: jsonb("reply_to").$type<Array<{ name?: string | null; address?: string | null }>>(),
        preview: text("preview"),
        flags: jsonb("flags").$type<string[]>(),
        seen: boolean("seen").notNull().default(false),
        flagged: boolean("flagged").notNull().default(false),
        hasAttachments: boolean("has_attachments").notNull().default(false),
        size: bigint("size", { mode: "number" }),
        sentAt: timestamp("sent_at", { withTimezone: true }),
        receivedAt: timestamp("received_at", { withTimezone: true }),

        createdAt: timestamp("created_at", { withTimezone: true })
            .notNull()
            .defaultNow(),
        updatedAt: timestamp("updated_at", { withTimezone: true }),
    },
    (table) => ({
        mailboxUidKey: uniqueIndex("email_messages_mailbox_uid_key")
            .on(table.mailboxId, table.uid),
        accountMailboxIdx: index("email_messages_account_mailbox_idx")
            .on(table.accountId, table.mailboxPath),
        receivedIdx: index("email_messages_received_idx")
            .on(table.receivedAt),
        messageIdIdx: index("email_messages_message_id_idx")
            .on(table.messageId),
        threadIdx: index("email_messages_thread_idx")
            .on(table.threadId),
    }),
)

export const emailMessageBodies = pgTable("email_message_bodies", {
    messageId: uuid("message_id")
        .primaryKey()
        .references(() => emailMessages.id, { onDelete: "cascade", onUpdate: "cascade" }),

    text: text("text"),
    html: text("html"),

    createdAt: timestamp("created_at", { withTimezone: true })
        .notNull()
        .defaultNow(),
    updatedAt: timestamp("updated_at", { withTimezone: true }),
})

export const emailAttachments = pgTable(
    "email_attachments",
    {
        id: uuid("id").primaryKey().defaultRandom(),

        messageId: uuid("message_id")
            .notNull()
            .references(() => emailMessages.id, { onDelete: "cascade", onUpdate: "cascade" }),

        filename: text("filename"),
        contentType: text("content_type"),
        contentId: text("content_id"),
        disposition: text("disposition"),
        size: bigint("size", { mode: "number" }),
        checksum: text("checksum"),
        storageKey: text("storage_key"),

        createdAt: timestamp("created_at", { withTimezone: true })
            .notNull()
            .defaultNow(),
    },
    (table) => ({
        messageIdx: index("email_attachments_message_idx")
            .on(table.messageId),
    }),
)

export const emailSyncState = pgTable(
    "email_sync_state",
    {
        id: uuid("id").primaryKey().defaultRandom(),

        tenantId: bigint("tenant_id", { mode: "number" })
            .notNull()
            .references(() => tenants.id, { onDelete: "cascade", onUpdate: "cascade" }),

        userId: uuid("user_id")
            .notNull()
            .references(() => authUsers.id, { onDelete: "cascade", onUpdate: "cascade" }),

        accountId: uuid("account_id")
            .notNull()
            .references(() => userCredentials.id, { onDelete: "cascade", onUpdate: "cascade" }),

        mailboxId: uuid("mailbox_id")
            .notNull()
            .references(() => emailMailboxes.id, { onDelete: "cascade", onUpdate: "cascade" }),

        mailboxPath: text("mailbox_path").notNull(),
        uidValidity: bigint("uid_validity", { mode: "number" }),
        highestUid: bigint("highest_uid", { mode: "number" }).notNull().default(0),
        modSeq: text("mod_seq"),
        lastSyncedAt: timestamp("last_synced_at", { withTimezone: true }),
        syncError: text("sync_error"),

        createdAt: timestamp("created_at", { withTimezone: true })
            .notNull()
            .defaultNow(),
        updatedAt: timestamp("updated_at", { withTimezone: true }),
    },
    (table) => ({
        mailboxKey: uniqueIndex("email_sync_state_mailbox_key")
            .on(table.accountId, table.mailboxPath),
        tenantAccountIdx: index("email_sync_state_tenant_account_idx")
            .on(table.tenantId, table.accountId),
    }),
)

export type EmailMailbox = typeof emailMailboxes.$inferSelect
export type NewEmailMailbox = typeof emailMailboxes.$inferInsert
export type EmailMessage = typeof emailMessages.$inferSelect
export type NewEmailMessage = typeof emailMessages.$inferInsert
export type EmailMessageBody = typeof emailMessageBodies.$inferSelect
export type NewEmailMessageBody = typeof emailMessageBodies.$inferInsert
export type EmailAttachment = typeof emailAttachments.$inferSelect
export type NewEmailAttachment = typeof emailAttachments.$inferInsert
export type EmailSyncState = typeof emailSyncState.$inferSelect
export type NewEmailSyncState = typeof emailSyncState.$inferInsert
