import "server-only";

import { unstable_cache } from "next/cache";
import { Query } from "node-appwrite";

import { DATABASE_ID, TABLES, type Activity, type Customer, type Property } from "./schema";
import { createAdminClient } from "./server";

function buildSixMonthKeys() {
  const months: Record<string, number> = {};
  for (let i = 5; i >= 0; i--) {
    const d = new Date();
    d.setDate(1);
    d.setMonth(d.getMonth() - i);
    months[d.toLocaleString("tr-TR", { month: "short", year: "2-digit" })] = 0;
  }
  return months;
}

function buildMonthlyTrend(properties: Property[]) {
  const months = buildSixMonthKeys();
  for (const p of properties) {
    const key = new Date(p.$createdAt).toLocaleString("tr-TR", { month: "short", year: "2-digit" });
    if (key in months) months[key]++;
  }
  return Object.entries(months).map(([ay, ilanSayisi]) => ({ ay, ilanSayisi }));
}

function buildCustomerMonthlyTrend(customers: Customer[]) {
  const months = buildSixMonthKeys();
  for (const c of customers) {
    const key = new Date(c.$createdAt).toLocaleString("tr-TR", { month: "short", year: "2-digit" });
    if (key in months) months[key]++;
  }
  return Object.entries(months).map(([ay, musteriSayisi]) => ({ ay, musteriSayisi }));
}

function buildActivityMonthlyTrend(activities: Activity[]) {
  const months = buildSixMonthKeys();
  for (const a of activities) {
    const key = new Date(a.$createdAt).toLocaleString("tr-TR", { month: "short", year: "2-digit" });
    if (key in months) months[key]++;
  }
  return Object.entries(months).map(([ay, aktiviteSayisi]) => ({ ay, aktiviteSayisi }));
}

const PROPERTY_TYPE_LABELS: Record<string, string> = {
  daire: "Daire",
  villa: "Villa",
  arsa: "Arsa",
  dukkan: "Dükkan",
  ofis: "Ofis",
  depo: "Depo",
};

function buildPropertyDistribution(properties: Property[]) {
  const counts: Record<string, number> = {};
  for (const p of properties) {
    counts[p.propertyType] = (counts[p.propertyType] ?? 0) + 1;
  }
  return Object.entries(counts)
    .filter(([, n]) => n > 0)
    .sort((a, b) => b[1] - a[1])
    .map(([tip, sayi]) => ({ tip, label: PROPERTY_TYPE_LABELS[tip] ?? tip, sayi }));
}

export type DashboardStats = {
  aktifIlanlar: number;
  satilikAktif: number;
  kiralikAktif: number;
  toplamMusteri: number;
  aliciMusteri: number;
  kiraciMusteri: number;
  yatirimciMusteri: number;
  rezerveIlanlar: number;
  bekleyenEslesmeler: number;
  buAyIlanlar: number;
  sonAktiviteler: Activity[];
  sonIlanlar: Property[];
  aylikTrend: { ay: string; ilanSayisi: number }[];
  aylikMusteriTrend: { ay: string; musteriSayisi: number }[];
  aylikAktiviteTrend: { ay: string; aktiviteSayisi: number }[];
  portfoyDagilim: { tip: string; label: string; sayi: number }[];
  takipMusteri: Customer[];
};

async function _getDashboardStats(tenantId: string): Promise<DashboardStats> {
  const { tablesDB } = createAdminClient();

  const today = new Date();
  today.setHours(23, 59, 59, 999);

  const thisMonthStart = new Date();
  thisMonthStart.setDate(1);
  thisMonthStart.setHours(0, 0, 0, 0);

  const sixMonthsAgo = new Date();
  sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6);
  sixMonthsAgo.setDate(1);
  sixMonthsAgo.setHours(0, 0, 0, 0);

  const base = (extra: string[]) => [Query.equal("tenantId", tenantId), ...extra, Query.limit(1)];
  const trend = (table: string) => [
    Query.equal("tenantId", tenantId),
    Query.greaterThanEqual("$createdAt", sixMonthsAgo.toISOString()),
    Query.orderAsc("$createdAt"),
    Query.limit(500),
  ];

  // Split into two sequential batches to avoid overwhelming the connection pool
  // with too many simultaneous requests to the same Appwrite host.
  const [
    aktifRes, satilikRes, kiralikRes,
    musteriRes, aliciRes, kiraciRes, yatirimciRes,
    eslesmelerRes, buAyRes,
  ] = await Promise.all([
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.properties, queries: base([Query.equal("status", "aktif")]) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.properties, queries: base([Query.equal("status", "aktif"), Query.equal("listingType", "satilik")]) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.properties, queries: base([Query.equal("status", "aktif"), Query.equal("listingType", "kiralik")]) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.customers, queries: base([]) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.customers, queries: base([Query.equal("type", "alici")]) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.customers, queries: base([Query.equal("type", "kiraci")]) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.customers, queries: base([Query.equal("type", "yatirimci")]) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.propertyMatches, queries: base([Query.equal("notified", false)]) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.properties, queries: base([Query.greaterThanEqual("$createdAt", thisMonthStart.toISOString())]) }),
  ]);

  const [
    aktivitelerRes, ilanlarRes,
    ilanTrendRes, musteriTrendRes, aktiviteTrendRes,
    aktifPropAllRes,
    takipRes, rezerveRes,
  ] = await Promise.all([
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.activities, queries: [Query.equal("tenantId", tenantId), Query.orderDesc("$createdAt"), Query.limit(6)] }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.properties, queries: [Query.equal("tenantId", tenantId), Query.orderDesc("$createdAt"), Query.limit(5)] }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.properties, queries: trend(TABLES.properties) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.customers, queries: trend(TABLES.customers) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.activities, queries: trend(TABLES.activities) }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.properties, queries: [Query.equal("tenantId", tenantId), Query.equal("status", "aktif"), Query.limit(500)] }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.customers, queries: [Query.equal("tenantId", tenantId), Query.lessThanEqual("nextFollowUpDate", today.toISOString()), Query.orderAsc("nextFollowUpDate"), Query.limit(10)] }),
    tablesDB.listRows({ databaseId: DATABASE_ID, tableId: TABLES.properties, queries: base([Query.equal("status", "rezerve")]) }),
  ]);

  const parse = <T>(res: { rows: unknown[] }) => JSON.parse(JSON.stringify(res.rows)) as T[];

  return {
    aktifIlanlar: aktifRes.total,
    satilikAktif: satilikRes.total,
    kiralikAktif: kiralikRes.total,
    toplamMusteri: musteriRes.total,
    aliciMusteri: aliciRes.total,
    kiraciMusteri: kiraciRes.total,
    yatirimciMusteri: yatirimciRes.total,
    bekleyenEslesmeler: eslesmelerRes.total,
    buAyIlanlar: buAyRes.total,
    rezerveIlanlar: rezerveRes.total,
    sonAktiviteler: parse<Activity>(aktivitelerRes),
    sonIlanlar: parse<Property>(ilanlarRes),
    aylikTrend: buildMonthlyTrend(parse<Property>(ilanTrendRes)),
    aylikMusteriTrend: buildCustomerMonthlyTrend(parse<Customer>(musteriTrendRes)),
    aylikAktiviteTrend: buildActivityMonthlyTrend(parse<Activity>(aktiviteTrendRes)),
    portfoyDagilim: buildPropertyDistribution(parse<Property>(aktifPropAllRes)),
    takipMusteri: parse<Customer>(takipRes),
  };
}

// Cache per-tenant for 30 seconds. Reduces Appwrite round-trips on slow
// connections; revalidated automatically when the tag is purged on mutations.
export const getDashboardStats = unstable_cache(
  _getDashboardStats,
  ["dashboard-stats"],
  { revalidate: 30 },
);
