import "server-only";

import { Query } from "node-appwrite";

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

export type JobCounterpart = {
  tenantId: string;
  companyName: string;
  kind: TenantKind;
};

export type JobWithCounterpart = Job & {
  counterpart: JobCounterpart | null;
};

async function fetchTenants(tenantIds: string[]): Promise<Map<string, JobCounterpart>> {
  if (tenantIds.length === 0) return new Map();
  const { tablesDB } = createAdminClient();
  const result = await tablesDB.listRows({
    databaseId: DATABASE_ID,
    tableId: TABLES.tenantSettings,
    queries: [Query.equal("tenantId", tenantIds), Query.limit(200)],
  });
  const map = new Map<string, JobCounterpart>();
  for (const row of result.rows as unknown as TenantSettings[]) {
    map.set(row.tenantId, {
      tenantId: row.tenantId,
      companyName: row.companyName,
      kind: row.kind,
    });
  }
  return map;
}

function enrichJob(j: Job, counterpartId: string, map: Map<string, JobCounterpart>): JobWithCounterpart {
  return { ...j, counterpart: map.get(counterpartId) ?? null };
}

export type JobListFilters = {
  status?: string;
  location?: string;
  /** Free-text matched client-side against patientCode + counterpart name. */
  q?: string;
};

async function listJobsFor(
  side: "lab" | "clinic",
  tenantId: string,
  filters: JobListFilters = {},
): Promise<JobWithCounterpart[]> {
  const { tablesDB } = createAdminClient();
  const sideField = side === "lab" ? "labTenantId" : "clinicTenantId";
  const queries = [
    Query.equal(sideField, tenantId),
    Query.orderDesc("$createdAt"),
    Query.limit(200),
  ];
  if (filters.status) queries.unshift(Query.equal("status", filters.status));
  if (filters.location) queries.unshift(Query.equal("location", filters.location));

  const result = await tablesDB.listRows({
    databaseId: DATABASE_ID,
    tableId: TABLES.jobs,
    queries,
  });
  const jobs = result.rows as unknown as Job[];
  const counterpartField = side === "lab" ? "clinicTenantId" : "labTenantId";
  const map = await fetchTenants(
    Array.from(new Set(jobs.map((j) => j[counterpartField]))),
  );
  const enriched = jobs.map((j) => enrichJob(j, j[counterpartField], map));

  // Free-text filter applied after fetch — only against the fields a user
  // would actually type (patient code, counterpart company name).
  const q = filters.q?.trim().toLocaleLowerCase("tr-TR");
  const filtered = q
    ? enriched.filter((j) => {
        const hay = `${j.patientCode} ${j.counterpart?.companyName ?? ""}`
          .toLocaleLowerCase("tr-TR");
        return hay.includes(q);
      })
    : enriched;

  return toPlain(filtered);
}

/** Inbound for a lab tenant — jobs the lab has received. */
export async function listInboundJobs(
  labTenantId: string,
  filters: JobListFilters = {},
): Promise<JobWithCounterpart[]> {
  return listJobsFor("lab", labTenantId, filters);
}

/** Outbound for a clinic tenant — jobs the clinic has sent. */
export async function listOutboundJobs(
  clinicTenantId: string,
  filters: JobListFilters = {},
): Promise<JobWithCounterpart[]> {
  return listJobsFor("clinic", clinicTenantId, filters);
}

/** For clinic's "Yeni İş Yayınla" form: list approved labs they can send to. */
export async function listApprovedLabsForClinic(
  clinicTenantId: string,
): Promise<JobCounterpart[]> {
  const { tablesDB } = createAdminClient();
  const result = await tablesDB.listRows({
    databaseId: DATABASE_ID,
    tableId: TABLES.connections,
    queries: [
      Query.equal("clinicTenantId", clinicTenantId),
      Query.equal("status", "approved"),
      Query.limit(100),
    ],
  });
  const labIds = (result.rows as unknown as { labTenantId: string }[]).map(
    (r) => r.labTenantId,
  );
  const map = await fetchTenants(labIds);
  return toPlain(
    labIds
      .map((id) => map.get(id))
      .filter((v): v is JobCounterpart => Boolean(v)),
  );
}
