import "server-only";

import { Query } from "node-appwrite";

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

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

export type ConnectionWithCounterpart = Connection & {
  counterpart: CounterpartTenant | null;
};

function counterpartTenantId(conn: Connection, selfTenantId: string): string {
  return conn.clinicTenantId === selfTenantId ? conn.labTenantId : conn.clinicTenantId;
}

async function fetchCounterparts(tenantIds: string[]): Promise<Map<string, CounterpartTenant>> {
  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(100)],
  });
  const map = new Map<string, CounterpartTenant>();
  for (const row of result.rows as unknown as TenantSettings[]) {
    map.set(row.tenantId, {
      tenantId: row.tenantId,
      companyName: row.companyName,
      memberNumber: row.memberNumber,
      kind: row.kind,
    });
  }
  return map;
}

async function enrich(
  rows: Connection[],
  selfTenantId: string,
): Promise<ConnectionWithCounterpart[]> {
  const counterpartIds = Array.from(
    new Set(rows.map((r) => counterpartTenantId(r, selfTenantId))),
  );
  const map = await fetchCounterparts(counterpartIds);
  return toPlain(
    rows.map((r) => ({
      ...r,
      counterpart: map.get(counterpartTenantId(r, selfTenantId)) ?? null,
    })),
  );
}

async function listConnectionsByStatus(
  tenantId: string,
  status: Connection["status"],
): Promise<Connection[]> {
  const { tablesDB } = createAdminClient();
  const result = await tablesDB.listRows({
    databaseId: DATABASE_ID,
    tableId: TABLES.connections,
    queries: [
      Query.or([
        Query.equal("clinicTenantId", tenantId),
        Query.equal("labTenantId", tenantId),
      ]),
      Query.equal("status", status),
      Query.orderDesc("$createdAt"),
      Query.limit(100),
    ],
  });
  return result.rows as unknown as Connection[];
}

export async function listApprovedConnections(
  tenantId: string,
): Promise<ConnectionWithCounterpart[]> {
  const rows = await listConnectionsByStatus(tenantId, "approved");
  return enrich(rows, tenantId);
}

export async function listPendingInbound(
  tenantId: string,
  selfUserId: string,
): Promise<ConnectionWithCounterpart[]> {
  // Pending requests sent TO this tenant (this tenant must approve/reject).
  const rows = await listConnectionsByStatus(tenantId, "pending");
  const inbound = rows.filter((r) => r.requestedBy !== selfUserId);
  return enrich(inbound, tenantId);
}

export async function listPendingOutbound(
  tenantId: string,
  selfUserId: string,
): Promise<ConnectionWithCounterpart[]> {
  // Pending requests this tenant sent — counterpart will approve/reject.
  const rows = await listConnectionsByStatus(tenantId, "pending");
  const outbound = rows.filter((r) => r.requestedBy === selfUserId);
  return enrich(outbound, tenantId);
}
