import { prisma } from "@/core/storage/prisma";
import type { Prisma } from "@prisma/client";
import type { CompanyId } from "@/core/auth/types";
import type { RegistryEntry } from "@/modules/registratura/types";
import {
  getDeadlineDisplayStatus,
} from "@/modules/registratura/services/deadline-service";
import { getDeadlineType } from "@/modules/registratura/services/deadline-catalog";
import { sendEmail } from "./email-service";
import type {
  NotificationPreference,
  NotificationType,
  DigestSection,
  DigestItem,
  DigestResult,
} from "./types";
import { defaultPreference } from "./types";

const NAMESPACE = "notifications";

// ── Preference CRUD (KeyValueStore) ──

export async function getPreference(
  userId: string,
): Promise<NotificationPreference | null> {
  const row = await prisma.keyValueStore.findUnique({
    where: { namespace_key: { namespace: NAMESPACE, key: `pref:${userId}` } },
  });
  if (!row) return null;
  return row.value as unknown as NotificationPreference;
}

export async function savePreference(
  pref: NotificationPreference,
): Promise<void> {
  await prisma.keyValueStore.upsert({
    where: {
      namespace_key: { namespace: NAMESPACE, key: `pref:${pref.userId}` },
    },
    update: { value: pref as unknown as Prisma.InputJsonValue },
    create: {
      namespace: NAMESPACE,
      key: `pref:${pref.userId}`,
      value: pref as unknown as Prisma.InputJsonValue,
    },
  });
}

export async function getAllPreferences(): Promise<NotificationPreference[]> {
  const rows = await prisma.keyValueStore.findMany({
    where: { namespace: NAMESPACE },
  });
  return rows
    .filter((r) => r.key.startsWith("pref:"))
    .map((r) => r.value as unknown as NotificationPreference);
}

// ── Load registry entries (direct Prisma — avoids N+1) ──

async function loadAllRegistryEntries(): Promise<RegistryEntry[]> {
  const rows = await prisma.keyValueStore.findMany({
    where: { namespace: "registratura" },
    select: { key: true, value: true },
  });

  return rows
    .filter((r) => r.key.startsWith("entry:"))
    .map((r) => r.value as unknown as RegistryEntry);
}

// ── Build digest for a company ──

function buildCompanyDigest(
  entries: RegistryEntry[],
  company: CompanyId,
): DigestSection[] {
  // "group" users see ALL entries across all companies
  const companyEntries =
    company === "group"
      ? entries
      : entries.filter((e) => e.company === company);
  const sections: DigestSection[] = [];

  const now = new Date();
  now.setHours(0, 0, 0, 0);

  // ── Deadline sections ──
  const urgentItems: DigestItem[] = [];
  const overdueItems: DigestItem[] = [];

  for (const entry of companyEntries) {
    if (entry.status !== "deschis") continue;

    for (const dl of entry.trackedDeadlines ?? []) {
      if (dl.resolution !== "pending") continue;

      const status = getDeadlineDisplayStatus(dl);
      const def = getDeadlineType(dl.typeId);
      const label = def?.label ?? dl.typeId;

      if (status.variant === "yellow" && status.daysRemaining !== null) {
        urgentItems.push({
          entryNumber: entry.number,
          subject: entry.subject,
          label,
          dueDate: dl.dueDate,
          daysRemaining: status.daysRemaining,
          color: "yellow",
        });
      }

      if (status.variant === "red" && status.daysRemaining !== null) {
        overdueItems.push({
          entryNumber: entry.number,
          subject: entry.subject,
          label,
          dueDate: dl.dueDate,
          daysRemaining: status.daysRemaining,
          color: "red",
        });
      }

      // Tacit approval (overdue but applicable) — also report
      if (status.variant === "blue" && status.daysRemaining !== null && status.daysRemaining < 0) {
        overdueItems.push({
          entryNumber: entry.number,
          subject: entry.subject,
          label: `${label} (aprobat tacit)`,
          dueDate: dl.dueDate,
          daysRemaining: status.daysRemaining,
          color: "blue",
        });
      }
    }
  }

  if (urgentItems.length > 0) {
    sections.push({
      type: "deadline-urgent",
      title: "Termene urgente (5 zile sau mai putin)",
      items: urgentItems.sort((a, b) => a.daysRemaining - b.daysRemaining),
    });
  }

  if (overdueItems.length > 0) {
    sections.push({
      type: "deadline-overdue",
      title: "Termene depasite",
      items: overdueItems.sort((a, b) => a.daysRemaining - b.daysRemaining),
    });
  }

  // ── Document expiry section ──
  const expiryItems: DigestItem[] = [];

  for (const entry of companyEntries) {
    if (entry.status !== "deschis" || !entry.expiryDate) continue;

    const expiry = new Date(entry.expiryDate);
    expiry.setHours(0, 0, 0, 0);
    const daysLeft = Math.ceil(
      (expiry.getTime() - now.getTime()) / (1000 * 60 * 60 * 24),
    );
    const alertDays = entry.expiryAlertDays ?? 30;

    if (daysLeft <= alertDays) {
      expiryItems.push({
        entryNumber: entry.number,
        subject: entry.subject,
        label: daysLeft < 0 ? "Expirat" : "Expira curand",
        dueDate: entry.expiryDate,
        daysRemaining: daysLeft,
        color: daysLeft < 0 ? "red" : "yellow",
      });
    }
  }

  if (expiryItems.length > 0) {
    sections.push({
      type: "document-expiry",
      title: "Documente care expira",
      items: expiryItems.sort((a, b) => a.daysRemaining - b.daysRemaining),
    });
  }

  return sections;
}

// ── Render HTML digest ──

function formatDateRo(dateStr: string): string {
  const d = new Date(dateStr);
  const day = String(d.getDate()).padStart(2, "0");
  const month = String(d.getMonth() + 1).padStart(2, "0");
  const year = d.getFullYear();
  return `${day}.${month}.${year}`;
}

function renderDigestHtml(
  sections: DigestSection[],
  companyName: string,
  date: string,
): string {
  const colorMap: Record<string, string> = {
    red: "#ef4444",
    yellow: "#f59e0b",
    blue: "#3b82f6",
  };

  const bgMap: Record<string, string> = {
    red: "#fef2f2",
    yellow: "#fffbeb",
    blue: "#eff6ff",
  };

  let sectionsHtml = "";

  for (const section of sections) {
    let rowsHtml = "";
    for (const item of section.items) {
      const daysText =
        item.daysRemaining < 0
          ? `${Math.abs(item.daysRemaining)} zile depasit`
          : item.daysRemaining === 0
            ? "Azi"
            : `${item.daysRemaining} zile ramase`;

      rowsHtml += `
        <tr style="border-bottom: 1px solid #e5e7eb;">
          <td style="padding: 8px 12px; font-size: 13px; color: #374151;">${item.entryNumber}</td>
          <td style="padding: 8px 12px; font-size: 13px; color: #374151; max-width: 250px; overflow: hidden; text-overflow: ellipsis;">${item.subject}</td>
          <td style="padding: 8px 12px; font-size: 13px; color: #374151;">${item.label}</td>
          <td style="padding: 8px 12px; font-size: 13px; color: #374151;">${formatDateRo(item.dueDate)}</td>
          <td style="padding: 8px 12px; font-size: 13px; font-weight: 600; color: ${colorMap[item.color] ?? "#374151"}; background: ${bgMap[item.color] ?? "transparent"}; border-radius: 4px;">${daysText}</td>
        </tr>`;
    }

    sectionsHtml += `
      <div style="margin-bottom: 24px;">
        <h3 style="margin: 0 0 8px 0; font-size: 15px; font-weight: 600; color: #111827;">${section.title} (${section.items.length})</h3>
        <table style="width: 100%; border-collapse: collapse; border: 1px solid #e5e7eb; border-radius: 6px; overflow: hidden;">
          <thead>
            <tr style="background: #f9fafb;">
              <th style="padding: 8px 12px; font-size: 12px; font-weight: 600; color: #6b7280; text-align: left;">Nr.</th>
              <th style="padding: 8px 12px; font-size: 12px; font-weight: 600; color: #6b7280; text-align: left;">Subiect</th>
              <th style="padding: 8px 12px; font-size: 12px; font-weight: 600; color: #6b7280; text-align: left;">Termen</th>
              <th style="padding: 8px 12px; font-size: 12px; font-weight: 600; color: #6b7280; text-align: left;">Scadent</th>
              <th style="padding: 8px 12px; font-size: 12px; font-weight: 600; color: #6b7280; text-align: left;">Status</th>
            </tr>
          </thead>
          <tbody>
            ${rowsHtml}
          </tbody>
        </table>
      </div>`;
  }

  return `<!DOCTYPE html>
<html>
<head><meta charset="utf-8" /></head>
<body style="margin: 0; padding: 0; background: #f3f4f6; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
  <div style="max-width: 700px; margin: 0 auto; padding: 24px;">
    <div style="background: #ffffff; border-radius: 8px; border: 1px solid #e5e7eb; overflow: hidden;">
      <!-- Header -->
      <div style="background: #111827; padding: 20px 24px;">
        <h1 style="margin: 0; font-size: 18px; font-weight: 600; color: #ffffff;">Alerte Termene &mdash; Digest zilnic</h1>
        <p style="margin: 4px 0 0 0; font-size: 13px; color: #9ca3af;">${companyName} &middot; ${formatDateRo(date)}</p>
      </div>

      <!-- Body -->
      <div style="padding: 24px;">
        ${sectionsHtml}

        <div style="margin-top: 24px; padding-top: 16px; border-top: 1px solid #e5e7eb;">
          <p style="margin: 0; font-size: 12px; color: #9ca3af;">
            Acest email este generat automat de ArchiTools. Poti dezactiva notificarile din
            <a href="https://tools.beletage.ro/registratura" style="color: #3b82f6; text-decoration: none;">Registratura</a>
            &rarr; butonul Notificari.
          </p>
        </div>
      </div>
    </div>
  </div>
</body>
</html>`;
}

// ── Company labels ──

const COMPANY_LABELS: Record<CompanyId, string> = {
  beletage: "Beletage",
  "urban-switch": "Urban Switch",
  "studii-de-teren": "Studii de Teren",
  group: "Grup",
};

// ── Main orchestrator ──

export async function runDigest(): Promise<DigestResult> {
  const result: DigestResult = {
    success: true,
    totalEmails: 0,
    errors: [],
    companySummary: {},
  };

  try {
    // 1. Load all entries + all preferences
    const [entries, preferences] = await Promise.all([
      loadAllRegistryEntries(),
      getAllPreferences(),
    ]);

    if (preferences.length === 0) {
      return { ...result, errors: ["Nu exista preferinte de notificare configurate"] };
    }

    // 2. Group subscribers by company
    const subscribersByCompany = new Map<CompanyId, NotificationPreference[]>();

    for (const pref of preferences) {
      if (pref.globalOptOut) continue;
      if (pref.enabledTypes.length === 0) continue;

      const existing = subscribersByCompany.get(pref.company) ?? [];
      existing.push(pref);
      subscribersByCompany.set(pref.company, existing);
    }

    // 3. Build digest per company, send per subscriber
    const today = new Date().toISOString().slice(0, 10);

    for (const [company, subscribers] of subscribersByCompany.entries()) {
      const allSections = buildCompanyDigest(entries, company);

      if (allSections.length === 0) {
        result.companySummary[company] = { emails: 0, sections: 0 };
        continue;
      }

      let emailsSent = 0;

      for (const subscriber of subscribers) {
        // Filter sections per subscriber's enabled types
        const userSections = allSections.filter((s) =>
          subscriber.enabledTypes.includes(s.type),
        );

        if (userSections.length === 0) continue;

        const totalItems = userSections.reduce(
          (acc, s) => acc + s.items.length,
          0,
        );

        const html = renderDigestHtml(
          userSections,
          COMPANY_LABELS[company] ?? company,
          today,
        );

        const subject = `${totalItems} alerte termene - ${COMPANY_LABELS[company] ?? company} (${formatDateRo(today)})`;

        try {
          await sendEmail({
            to: subscriber.email,
            subject,
            html,
          });
          emailsSent++;
          result.totalEmails++;
        } catch (err) {
          const msg = `Eroare trimitere email catre ${subscriber.email}: ${err instanceof Error ? err.message : String(err)}`;
          result.errors.push(msg);
        }
      }

      result.companySummary[company] = {
        emails: emailsSent,
        sections: allSections.length,
      };
    }
  } catch (err) {
    result.success = false;
    result.errors.push(
      `Eroare generala digest: ${err instanceof Error ? err.message : String(err)}`,
    );
  }

  return result;
}

// ── Test digest — sends sample email to all subscribers ──

export async function sendTestDigest(): Promise<DigestResult> {
  const result: DigestResult = {
    success: true,
    totalEmails: 0,
    errors: [],
    companySummary: {},
  };

  try {
    const preferences = await getAllPreferences();

    if (preferences.length === 0) {
      return { ...result, errors: ["Nu exista preferinte de notificare configurate"] };
    }

    const today = new Date().toISOString().slice(0, 10);

    // Sample data for testing
    const testSections: DigestSection[] = [
      {
        type: "deadline-urgent",
        title: "Termene urgente (5 zile sau mai putin)",
        items: [
          {
            entryNumber: "B-2026-00001",
            subject: "[TEST] Certificat de urbanism - str. Exemplu nr. 10",
            label: "Emitere CU (30 zile lucratoare)",
            dueDate: today,
            daysRemaining: 2,
            color: "yellow",
          },
          {
            entryNumber: "B-2026-00005",
            subject: "[TEST] Aviz ISU - Proiect rezidential",
            label: "Raspuns aviz ISU (15 zile)",
            dueDate: today,
            daysRemaining: 5,
            color: "yellow",
          },
        ],
      },
      {
        type: "deadline-overdue",
        title: "Termene depasite",
        items: [
          {
            entryNumber: "B-2026-00003",
            subject: "[TEST] Autorizatie construire - bloc P+4",
            label: "Emitere AC (30 zile lucratoare)",
            dueDate: "2026-03-01",
            daysRemaining: -10,
            color: "red",
          },
        ],
      },
      {
        type: "document-expiry",
        title: "Documente care expira",
        items: [
          {
            entryNumber: "B-2025-00010",
            subject: "[TEST] CU nr. 123/2025 - proiect mixt",
            label: "Expira curand",
            dueDate: "2026-03-25",
            daysRemaining: 14,
            color: "yellow",
          },
        ],
      },
    ];

    for (const pref of preferences) {
      if (pref.globalOptOut) continue;

      const companyName = COMPANY_LABELS[pref.company] ?? pref.company;
      const html = renderDigestHtml(testSections, companyName, today);
      const subject = `[TEST] 4 alerte termene - ${companyName} (${formatDateRo(today)})`;

      try {
        await sendEmail({ to: pref.email, subject, html });
        result.totalEmails++;
      } catch (err) {
        result.errors.push(
          `Eroare trimitere catre ${pref.email}: ${err instanceof Error ? err.message : String(err)}`,
        );
      }
    }

    result.companySummary["test"] = {
      emails: result.totalEmails,
      sections: testSections.length,
    };
  } catch (err) {
    result.success = false;
    result.errors.push(
      `Eroare test digest: ${err instanceof Error ? err.message : String(err)}`,
    );
  }

  return result;
}
