"use server";

import { Query } from "node-appwrite";

import { createAdminClient } from "./server";
import {
  DATABASE_ID,
  TABLES,
  type CalendarEvent,
  type Customer,
  type FinanceEntry,
  type Invoice,
  type Service,
  type Software,
  type Task,
} from "./schema";
import { requireTenant } from "./tenant-guard";

export type SearchHit = {
  id: string;
  title: string;
  subtitle?: string;
  url: string;
  group: SearchGroup;
};

export type SearchGroup =
  | "customers"
  | "invoices"
  | "tasks"
  | "services"
  | "software"
  | "events"
  | "finance";

export type SearchResults = Record<SearchGroup, SearchHit[]>;

const PAGE_LIMIT = 200; // per entity, plenty for search-time scan
const MAX_HITS_PER_GROUP = 8;

const TYPE_LABEL: Record<string, string> = {
  income: "Gelir",
  expense: "Gider",
  debt: "Borç",
  receivable: "Alacak",
};

function tryMatch(haystack: string | undefined | null, needle: string): boolean {
  if (!haystack) return false;
  return haystack.toLocaleLowerCase("tr-TR").includes(needle);
}

export async function globalSearchAction(rawQuery: string): Promise<SearchResults> {
  const empty: SearchResults = {
    customers: [],
    invoices: [],
    tasks: [],
    services: [],
    software: [],
    events: [],
    finance: [],
  };

  const q = rawQuery.trim().toLocaleLowerCase("tr-TR");
  if (!q || q.length < 2) return empty;

  let ctx;
  try {
    ctx = await requireTenant();
  } catch {
    return empty;
  }

  const { tablesDB } = createAdminClient();
  const tenantQ = [Query.equal("tenantId", ctx.tenantId), Query.limit(PAGE_LIMIT)];

  const [customers, invoices, tasks, services, software, events, finance] =
    await Promise.all([
      tablesDB
        .listRows({ databaseId: DATABASE_ID, tableId: TABLES.customers, queries: tenantQ })
        .catch(() => ({ rows: [] as unknown[] })),
      tablesDB
        .listRows({ databaseId: DATABASE_ID, tableId: TABLES.invoices, queries: tenantQ })
        .catch(() => ({ rows: [] as unknown[] })),
      tablesDB
        .listRows({ databaseId: DATABASE_ID, tableId: TABLES.tasks, queries: tenantQ })
        .catch(() => ({ rows: [] as unknown[] })),
      tablesDB
        .listRows({ databaseId: DATABASE_ID, tableId: TABLES.services, queries: tenantQ })
        .catch(() => ({ rows: [] as unknown[] })),
      tablesDB
        .listRows({ databaseId: DATABASE_ID, tableId: TABLES.software, queries: tenantQ })
        .catch(() => ({ rows: [] as unknown[] })),
      tablesDB
        .listRows({ databaseId: DATABASE_ID, tableId: TABLES.calendarEvents, queries: tenantQ })
        .catch(() => ({ rows: [] as unknown[] })),
      tablesDB
        .listRows({ databaseId: DATABASE_ID, tableId: TABLES.financeEntries, queries: tenantQ })
        .catch(() => ({ rows: [] as unknown[] })),
    ]);

  const customerMap = new Map<string, string>();
  for (const c of customers.rows as unknown as Customer[]) {
    customerMap.set(c.$id, c.name);
  }

  // ---------- Customers ----------
  const customerHits: SearchHit[] = [];
  for (const c of customers.rows as unknown as Customer[]) {
    if (
      tryMatch(c.name, q) ||
      tryMatch(c.email, q) ||
      tryMatch(c.phone, q) ||
      tryMatch(c.taxId, q)
    ) {
      customerHits.push({
        id: c.$id,
        title: c.name,
        subtitle: c.email || c.phone || c.taxId || undefined,
        url: "/customers",
        group: "customers",
      });
      if (customerHits.length >= MAX_HITS_PER_GROUP) break;
    }
  }

  // ---------- Invoices ----------
  const invoiceHits: SearchHit[] = [];
  for (const inv of invoices.rows as unknown as Invoice[]) {
    if (
      tryMatch(inv.number, q) ||
      tryMatch(inv.notes, q) ||
      tryMatch(customerMap.get(inv.customerId), q)
    ) {
      invoiceHits.push({
        id: inv.$id,
        title: inv.number,
        subtitle: customerMap.get(inv.customerId) ?? undefined,
        url: `/invoices/${inv.$id}`,
        group: "invoices",
      });
      if (invoiceHits.length >= MAX_HITS_PER_GROUP) break;
    }
  }

  // ---------- Tasks ----------
  const taskHits: SearchHit[] = [];
  for (const t of tasks.rows as unknown as Task[]) {
    if (tryMatch(t.title, q) || tryMatch(t.description, q)) {
      taskHits.push({
        id: t.$id,
        title: t.title,
        subtitle: t.description ? t.description.slice(0, 80) : undefined,
        url: "/tasks",
        group: "tasks",
      });
      if (taskHits.length >= MAX_HITS_PER_GROUP) break;
    }
  }

  // ---------- Services ----------
  const serviceHits: SearchHit[] = [];
  for (const s of services.rows as unknown as Service[]) {
    if (tryMatch(s.name, q) || tryMatch(s.description, q)) {
      serviceHits.push({
        id: s.$id,
        title: s.name,
        subtitle: customerMap.get(s.customerId) ?? undefined,
        url: "/services",
        group: "services",
      });
      if (serviceHits.length >= MAX_HITS_PER_GROUP) break;
    }
  }

  // ---------- Software ----------
  const softwareHits: SearchHit[] = [];
  for (const s of software.rows as unknown as Software[]) {
    if (tryMatch(s.name, q) || tryMatch(s.version, q) || tryMatch(s.description, q)) {
      softwareHits.push({
        id: s.$id,
        title: s.name,
        subtitle: s.version ? `v${s.version}` : undefined,
        url: "/software",
        group: "software",
      });
      if (softwareHits.length >= MAX_HITS_PER_GROUP) break;
    }
  }

  // ---------- Calendar events ----------
  const eventHits: SearchHit[] = [];
  for (const e of events.rows as unknown as CalendarEvent[]) {
    if (tryMatch(e.title, q) || tryMatch(e.description, q)) {
      eventHits.push({
        id: e.$id,
        title: e.title,
        subtitle: new Date(e.start).toLocaleDateString("tr-TR", {
          day: "2-digit",
          month: "short",
          year: "numeric",
        }),
        url: "/calendar",
        group: "events",
      });
      if (eventHits.length >= MAX_HITS_PER_GROUP) break;
    }
  }

  // ---------- Finance entries ----------
  const financeHits: SearchHit[] = [];
  for (const e of finance.rows as unknown as FinanceEntry[]) {
    const amountStr = e.amount.toString();
    if (
      tryMatch(e.description, q) ||
      tryMatch(customerMap.get(e.customerId ?? ""), q) ||
      tryMatch(amountStr, q)
    ) {
      financeHits.push({
        id: e.$id,
        title: `${TYPE_LABEL[e.type]} — ${e.amount.toLocaleString("tr-TR", { minimumFractionDigits: 2 })} ₺`,
        subtitle:
          (customerMap.get(e.customerId ?? "") || e.description || "").slice(0, 80) ||
          undefined,
        url: "/finance",
        group: "finance",
      });
      if (financeHits.length >= MAX_HITS_PER_GROUP) break;
    }
  }

  return {
    customers: customerHits,
    invoices: invoiceHits,
    tasks: taskHits,
    services: serviceHits,
    software: softwareHits,
    events: eventHits,
    finance: financeHits,
  };
}
