import { randomUUIDv7 } from 'bun';

import { getDb, pgGet } from '@/shared/db';
import { touchDevice } from '@/entities/device';
import { upsertConversation, listConversations } from '@/entities/conversation';
import { upsertMessage, listMessages } from '@/entities/message';
import type { Conversation } from '@/entities/conversation';
import type { Message, MessageFilter } from '@/entities/message';

export interface EmailAddressPayload {
  address: string;
  name?: string | null;
}

export interface EmailPayload {
  messageId: string;
  threadId?: string | null;
  subject?: string | null;
  fromAddress: string;
  fromName?: string | null;
  to?: EmailAddressPayload[] | null;
  cc?: EmailAddressPayload[] | null;
  folder: string;
  direction: 'incoming' | 'outgoing';
  textBody?: string | null;
  htmlBody?: string | null;
  hasAttachments?: boolean | null;
  attachmentCount?: number | null;
  sentAt: string;
  receivedAt?: string | null;
  isRead?: boolean | null;
}

export interface SyncMailPayload {
  emails: EmailPayload[];
}

export async function ingestMail(
  deviceId: string,
  payload: SyncMailPayload,
): Promise<{ synced: number; skipped: number }> {
  try {
    const db = getDb();
    let synced = 0;
    let skipped = 0;

    for (const email of payload.emails) {
      const existing = await pgGet<{ id: string }>(
        db,
        "SELECT id FROM macsync.messages WHERE device_id = $1 AND external_id = $2 AND provider = 'icloud'",
        [deviceId, email.messageId],
      );

      if (existing) {
        skipped++;
        continue;
      }

      const threadKey = email.threadId ?? email.subject ?? email.messageId;
      const convExternalId = `icloud-thread:${threadKey}`;

      const convId = randomUUIDv7();
      const conv = await upsertConversation(db, {
        id: convId,
        deviceId,
        externalId: convExternalId,
        displayName: email.subject ?? '(no subject)',
        isGroup: (email.to?.length ?? 0) + (email.cc?.length ?? 0) > 1,
        participants: [
          email.fromAddress,
          ...(email.to ?? []).map((a) => a.address),
        ],
        lastMessageAt: email.sentAt,
      });

      const body = email.textBody ?? email.htmlBody ?? '';
      await upsertMessage(db, {
        id: randomUUIDv7(),
        deviceId,
        conversationId: conv.id,
        externalId: email.messageId,
        provider: 'icloud',
        fromHandle: email.fromAddress,
        body,
        isFromMe: email.direction === 'outgoing',
        hasAttachments: email.hasAttachments ?? false,
        attachmentCount: email.attachmentCount ?? 0,
        sentAt: email.sentAt,
        deliveredAt: email.receivedAt ?? null,
        readAt: email.isRead ? email.sentAt : null,
      });

      synced++;
    }

    await touchDevice(db, deviceId);
    return { synced, skipped };
  } catch (err) {
    throw new Error(
      `ingestMail failed for device ${deviceId}: ${err instanceof Error ? err.message : String(err)}`,
      { cause: err },
    );
  }
}

export async function queryMailConversations(deviceId?: string): Promise<readonly Conversation[]> {
  try {
    const db = getDb();
    const all = await listConversations(db, deviceId);
    const filtered: Conversation[] = [];
    for (const c of all) {
      const msg = await pgGet<{ id: string }>(
        db,
        "SELECT id FROM macsync.messages WHERE conversation_id = $1 AND provider = 'icloud' LIMIT 1",
        [c.id],
      );
      if (msg) filtered.push(c);
    }
    return filtered;
  } catch (err) {
    throw new Error(
      `queryMailConversations failed: ${err instanceof Error ? err.message : String(err)}`,
      { cause: err },
    );
  }
}

export async function queryMailMessages(filter: MessageFilter): Promise<readonly Message[]> {
  try {
    return await listMessages(getDb(), { ...filter, provider: 'icloud' });
  } catch (err) {
    throw new Error(
      `queryMailMessages failed: ${err instanceof Error ? err.message : String(err)}`,
      { cause: err },
    );
  }
}

export async function getLastMailSync(deviceId: string): Promise<string | null> {
  try {
    const db = getDb();
    const row = await pgGet<{ last: string | null }>(
      db,
      "SELECT MAX(synced_at) as last FROM macsync.messages WHERE device_id = $1 AND provider = 'icloud'",
      [deviceId],
    );
    return row?.last ?? null;
  } catch (err) {
    throw new Error(
      `getLastMailSync failed for device ${deviceId}: ${err instanceof Error ? err.message : String(err)}`,
      { cause: err },
    );
  }
}

export async function getImailStats(
  deviceId: string,
): Promise<{ totalEmails: number; totalFolders: number; lastSyncAt: string | null }> {
  try {
    const db = getDb();
    const row = await pgGet<{ n: string }>(
      db,
      "SELECT COUNT(*) as n FROM macsync.messages WHERE device_id = $1 AND provider = 'icloud'",
      [deviceId],
    );
    return {
      totalEmails: row ? Number(row.n) : 0,
      totalFolders: 0,
      lastSyncAt: await getLastMailSync(deviceId),
    };
  } catch (err) {
    throw new Error(
      `getImailStats failed for device ${deviceId}: ${err instanceof Error ? err.message : String(err)}`,
      { cause: err },
    );
  }
}
