import "server-only";

import { Query } from "node-appwrite";

import { createAdminClient } from "./server";
import {
  DATABASE_ID,
  TABLES,
  type Customer,
  type FinanceEntry,
  type Invoice,
  type Task,
} from "./schema";

export type DashboardData = {
  metrics: {
    totalCustomers: number;
    activeCustomers: number;
    monthIncome: number; // current month income
    prevMonthIncome: number; // previous month income (for delta)
    outstanding: number; // unpaid invoices total (draft+sent+overdue)
    overdueCount: number;
    openTasks: number;
    urgentTasks: number;
  };
  monthlyIncome: { month: string; income: number; expense: number }[]; // last 12 months
  topCustomers: { name: string; total: number }[]; // top 5 by paid invoice total
  recentTransactions: {
    id: string;
    type: FinanceEntry["type"];
    amount: number;
    date: string;
    customerName: string;
    description: string;
  }[];
  topServices: { name: string; total: number; count: number }[]; // top 5 services by revenue (qty*unitPrice)
  newCustomersMonthly: { month: string; count: number }[]; // last 6 months
};

const MONTH_SHORT = ["Oca", "Şub", "Mar", "Nis", "May", "Haz", "Tem", "Ağu", "Eyl", "Eki", "Kas", "Ara"];

function monthKey(d: Date): string {
  return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
}

function monthLabel(d: Date): string {
  return MONTH_SHORT[d.getMonth()];
}

export async function getDashboardData(
  tenantId: string,
  currentUserId?: string,
): Promise<DashboardData> {
  const { tablesDB } = createAdminClient();

  const [customers, invoices, financeEntries, tasks, services] = await Promise.all([
    tablesDB
      .listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.customers,
        queries: [Query.equal("tenantId", tenantId), Query.limit(2000)],
      })
      .catch(() => ({ rows: [] as unknown[] })),
    tablesDB
      .listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.invoices,
        queries: [Query.equal("tenantId", tenantId), Query.limit(2000)],
      })
      .catch(() => ({ rows: [] as unknown[] })),
    tablesDB
      .listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.financeEntries,
        queries: [
          Query.equal("tenantId", tenantId),
          Query.orderDesc("date"),
          Query.limit(2000),
        ],
      })
      .catch(() => ({ rows: [] as unknown[] })),
    tablesDB
      .listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.tasks,
        queries: [Query.equal("tenantId", tenantId), Query.limit(2000)],
      })
      .catch(() => ({ rows: [] as unknown[] })),
    tablesDB
      .listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.services,
        queries: [Query.equal("tenantId", tenantId), Query.limit(2000)],
      })
      .catch(() => ({ rows: [] as unknown[] })),
  ]);

  const customerList = customers.rows as unknown as Customer[];
  const invoiceList = invoices.rows as unknown as Invoice[];
  const entryList = financeEntries.rows as unknown as FinanceEntry[];
  const taskList = tasks.rows as unknown as Task[];

  const customerMap = new Map(customerList.map((c) => [c.$id, c.name]));

  // ---------------- Metrics ----------------
  const now = new Date();
  const thisMonth = monthKey(now);
  const prev = new Date(now.getFullYear(), now.getMonth() - 1, 1);
  const prevMonth = monthKey(prev);

  let monthIncome = 0;
  let prevMonthIncome = 0;
  for (const e of entryList) {
    if (e.type !== "income") continue;
    const k = monthKey(new Date(e.date));
    if (k === thisMonth) monthIncome += e.amount;
    else if (k === prevMonth) prevMonthIncome += e.amount;
  }

  let outstanding = 0;
  let overdueCount = 0;
  const today = new Date();
  for (const inv of invoiceList) {
    const status = inv.status ?? "draft";
    if (status === "paid" || status === "cancelled") continue;
    outstanding += inv.total ?? 0;
    if (status === "overdue" || (inv.dueDate && new Date(inv.dueDate) < today)) {
      overdueCount += 1;
    }
  }

  let openTasks = 0;
  let urgentTasks = 0;
  for (const t of taskList) {
    if ((t.status ?? "todo") === "done") continue;
    // Personal scope: own assigned + unassigned. Falls back to all if no userId.
    if (currentUserId) {
      const assignee = t.assigneeId ?? "";
      if (assignee && assignee !== currentUserId) continue;
    }
    openTasks += 1;
    if ((t.priority ?? "medium") === "urgent") urgentTasks += 1;
  }

  const activeCustomers = customerList.filter((c) => (c.status ?? "active") === "active").length;

  // ---------------- Monthly income/expense (last 12 months) ----------------
  const monthSeries: DashboardData["monthlyIncome"] = [];
  for (let i = 11; i >= 0; i--) {
    const d = new Date(now.getFullYear(), now.getMonth() - i, 1);
    monthSeries.push({ month: monthLabel(d), income: 0, expense: 0 });
  }
  for (const e of entryList) {
    const ed = new Date(e.date);
    const monthsAgo =
      (now.getFullYear() - ed.getFullYear()) * 12 + (now.getMonth() - ed.getMonth());
    if (monthsAgo < 0 || monthsAgo > 11) continue;
    const idx = 11 - monthsAgo;
    if (e.type === "income") monthSeries[idx].income += e.amount;
    else if (e.type === "expense") monthSeries[idx].expense += e.amount;
  }

  // ---------------- Top customers (by paid invoice total) ----------------
  const customerRevenue = new Map<string, number>();
  for (const inv of invoiceList) {
    if (inv.status !== "paid") continue;
    customerRevenue.set(
      inv.customerId,
      (customerRevenue.get(inv.customerId) ?? 0) + (inv.total ?? 0),
    );
  }
  const topCustomers = Array.from(customerRevenue.entries())
    .map(([id, total]) => ({ name: customerMap.get(id) ?? "—", total }))
    .sort((a, b) => b.total - a.total)
    .slice(0, 5);

  // ---------------- Recent transactions (last 8) ----------------
  const recentTransactions = entryList.slice(0, 8).map((e) => ({
    id: e.$id,
    type: e.type,
    amount: e.amount,
    date: e.date,
    customerName: e.customerId ? customerMap.get(e.customerId) ?? "" : "",
    description: e.description ?? "",
  }));

  // ---------------- Top services (by current MRR estimate) ----------------
  const svcMap = new Map<string, { name: string; total: number; count: number }>();
  for (const s of services.rows as unknown as { name: string; unitPrice?: number }[]) {
    const key = s.name;
    const entry = svcMap.get(key) ?? { name: s.name, total: 0, count: 0 };
    entry.total += s.unitPrice ?? 0;
    entry.count += 1;
    svcMap.set(key, entry);
  }
  const topServices = Array.from(svcMap.values())
    .sort((a, b) => b.total - a.total)
    .slice(0, 5);

  // ---------------- New customers per month (last 6) ----------------
  const newCustomersMonthly: DashboardData["newCustomersMonthly"] = [];
  for (let i = 5; i >= 0; i--) {
    const d = new Date(now.getFullYear(), now.getMonth() - i, 1);
    newCustomersMonthly.push({ month: monthLabel(d), count: 0 });
  }
  for (const c of customerList) {
    const cd = new Date(c.$createdAt);
    const monthsAgo =
      (now.getFullYear() - cd.getFullYear()) * 12 + (now.getMonth() - cd.getMonth());
    if (monthsAgo < 0 || monthsAgo > 5) continue;
    const idx = 5 - monthsAgo;
    newCustomersMonthly[idx].count += 1;
  }

  return {
    metrics: {
      totalCustomers: customerList.length,
      activeCustomers,
      monthIncome,
      prevMonthIncome,
      outstanding,
      overdueCount,
      openTasks,
      urgentTasks,
    },
    monthlyIncome: monthSeries,
    topCustomers,
    recentTransactions,
    topServices,
    newCustomersMonthly,
  };
}
