import "server-only";

import { Query } from "node-appwrite";

import {
  DATABASE_ID,
  TABLES,
  type FinanceEntry,
  type Job,
  type Notification,
  type TenantKind,
  type TenantSettings,
} from "./schema";
import { createAdminClient } from "./server";
import { toPlain } from "./serialize";

export type DashboardJob = Job & {
  counterpartName: string | null;
};

export type DashboardData = {
  openJobsCount: number;
  pendingActionCount: number; // jobs awaiting MY action
  unreadCount: number;
  receivablePending: number; // lab perspective
  payablePending: number; // clinic perspective
  currency: string;
  approvedConnectionsCount: number;
  recentJobs: DashboardJob[];
  recentNotifications: Notification[];
};

export async function getDashboardData(
  tenantId: string,
  kind: TenantKind | null,
): Promise<DashboardData> {
  const { tablesDB } = createAdminClient();
  const isLab = kind === "lab";

  // Jobs that involve this tenant — limit to 10 most recent for the list,
  // count separately for the stat card.
  const jobsField = isLab ? "labTenantId" : "clinicTenantId";

  const [recentJobsRes, openJobsRes, pendingActionRes, financeRes, notifRes, unreadRes, connRes] =
    await Promise.all([
      tablesDB.listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.jobs,
        queries: [
          Query.equal(jobsField, tenantId),
          Query.orderDesc("$createdAt"),
          Query.limit(8),
        ],
      }),
      tablesDB.listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.jobs,
        queries: [
          Query.equal(jobsField, tenantId),
          Query.notEqual("status", "delivered"),
          Query.notEqual("status", "cancelled"),
          Query.limit(1),
        ],
      }),
      tablesDB.listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.jobs,
        queries: [
          Query.equal(jobsField, tenantId),
          Query.equal("status", isLab ? "pending" : "sent"),
          Query.limit(1),
        ],
      }),
      tablesDB.listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.financeEntries,
        queries: [
          Query.equal("tenantId", tenantId),
          Query.equal("status", "pending"),
          Query.limit(200),
        ],
      }),
      tablesDB.listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.notifications,
        queries: [
          Query.equal("tenantId", tenantId),
          Query.orderDesc("$createdAt"),
          Query.limit(5),
        ],
      }),
      tablesDB.listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.notifications,
        queries: [
          Query.equal("tenantId", tenantId),
          Query.equal("read", false),
          Query.limit(1),
        ],
      }),
      tablesDB.listRows({
        databaseId: DATABASE_ID,
        tableId: TABLES.connections,
        queries: [
          Query.or([
            Query.equal("clinicTenantId", tenantId),
            Query.equal("labTenantId", tenantId),
          ]),
          Query.equal("status", "approved"),
          Query.limit(1),
        ],
      }),
    ]);

  const recentJobs = recentJobsRes.rows as unknown as Job[];
  const counterpartIds = Array.from(
    new Set(
      recentJobs.map((j) => (isLab ? j.clinicTenantId : j.labTenantId)).filter(Boolean),
    ),
  );

  const counterpartMap = new Map<string, string>();
  if (counterpartIds.length > 0) {
    const counterpartsRes = await tablesDB.listRows({
      databaseId: DATABASE_ID,
      tableId: TABLES.tenantSettings,
      queries: [Query.equal("tenantId", counterpartIds), Query.limit(200)],
    });
    for (const s of counterpartsRes.rows as unknown as TenantSettings[]) {
      counterpartMap.set(s.tenantId, s.companyName);
    }
  }

  const finance = financeRes.rows as unknown as FinanceEntry[];
  let receivablePending = 0;
  let payablePending = 0;
  let currency = "TRY";
  for (const e of finance) {
    if (e.currency) currency = e.currency;
    if (e.type === "receivable") receivablePending += e.amount;
    if (e.type === "payable") payablePending += e.amount;
  }

  return toPlain({
    openJobsCount: openJobsRes.total,
    pendingActionCount: pendingActionRes.total,
    unreadCount: unreadRes.total,
    receivablePending,
    payablePending,
    currency,
    approvedConnectionsCount: connRes.total,
    recentJobs: recentJobs.map((j) => ({
      ...j,
      counterpartName:
        counterpartMap.get(isLab ? j.clinicTenantId : j.labTenantId) ?? null,
    })),
    recentNotifications: notifRes.rows as unknown as Notification[],
  });
}
