"use server";

import { revalidatePath } from "next/cache";
import { ID, Permission, Query, Role } from "node-appwrite";

import { logAudit } from "./audit";
import { DATABASE_ID, TABLES, type CardBrand, type SavedCard } from "./schema";
import { createAdminClient } from "./server";
import { requireRole, requireTenant } from "./tenant-guard";

const VALID_BRANDS: CardBrand[] = ["visa", "mastercard", "amex", "troy", "unknown"];

function teamCardPermissions(tenantId: string) {
  return [
    Permission.read(Role.team(tenantId, "owner")),
    Permission.read(Role.team(tenantId, "admin")),
    Permission.update(Role.team(tenantId, "owner")),
    Permission.delete(Role.team(tenantId, "owner")),
  ];
}

async function clearOtherDefaults(tenantId: string, exceptId?: string): Promise<void> {
  const { tablesDB } = createAdminClient();
  const result = await tablesDB.listRows({
    databaseId: DATABASE_ID,
    tableId: TABLES.savedCards,
    queries: [
      Query.equal("tenantId", tenantId),
      Query.equal("isDefault", true),
      Query.limit(20),
    ],
  });
  for (const row of result.rows) {
    if (exceptId && row.$id === exceptId) continue;
    await tablesDB.updateRow(DATABASE_ID, TABLES.savedCards, row.$id, {
      isDefault: false,
    });
  }
}

type SaveCardInput = {
  brand: string;
  last4: string;
  expiryMonth: number;
  expiryYear: number;
  holderName: string;
  makeDefault: boolean;
};

export async function persistCardFromMockCheckout(input: SaveCardInput): Promise<void> {
  const ctx = await requireTenant();
  requireRole(ctx, ["owner"]);

  const brand = (VALID_BRANDS as string[]).includes(input.brand)
    ? (input.brand as CardBrand)
    : "unknown";
  const last4 = input.last4.replace(/\D/g, "").slice(-4).padStart(4, "0");

  if (last4.length !== 4) throw new Error("Geçersiz kart son 4 hanesi.");
  if (input.expiryMonth < 1 || input.expiryMonth > 12) throw new Error("Geçersiz ay.");
  if (input.expiryYear < 2026 || input.expiryYear > 2099) throw new Error("Geçersiz yıl.");

  if (input.makeDefault) {
    await clearOtherDefaults(ctx.tenantId);
  }

  const { tablesDB } = createAdminClient();
  const row = await tablesDB.createRow(
    DATABASE_ID,
    TABLES.savedCards,
    ID.unique(),
    {
      tenantId: ctx.tenantId,
      createdBy: ctx.user.id,
      brand,
      last4,
      expiryMonth: input.expiryMonth,
      expiryYear: input.expiryYear,
      holderName: input.holderName.trim().slice(0, 128) || undefined,
      provider: "mock",
      isDefault: input.makeDefault,
    },
    teamCardPermissions(ctx.tenantId),
  );

  await logAudit({
    tenantId: ctx.tenantId,
    userId: ctx.user.id,
    action: "create",
    entityType: "saved_card",
    entityId: row.$id,
    changes: { brand, last4, isDefault: input.makeDefault },
  });

  revalidatePath("/settings/billing");
}

export async function setDefaultCardAction(formData: FormData): Promise<void> {
  const id = String(formData.get("id") ?? "");
  if (!id) throw new Error("ID eksik.");

  const ctx = await requireTenant();
  requireRole(ctx, ["owner"]);

  const { tablesDB } = createAdminClient();
  const existing = (await tablesDB.getRow(
    DATABASE_ID,
    TABLES.savedCards,
    id,
  )) as unknown as SavedCard;
  if (existing.tenantId !== ctx.tenantId) throw new Error("Erişim engellendi.");

  await clearOtherDefaults(ctx.tenantId, id);
  await tablesDB.updateRow(DATABASE_ID, TABLES.savedCards, id, { isDefault: true });

  await logAudit({
    tenantId: ctx.tenantId,
    userId: ctx.user.id,
    action: "update",
    entityType: "saved_card",
    entityId: id,
    changes: { isDefault: true },
  });

  revalidatePath("/settings/billing");
}

export async function removeCardAction(formData: FormData): Promise<void> {
  const id = String(formData.get("id") ?? "");
  if (!id) throw new Error("ID eksik.");

  const ctx = await requireTenant();
  requireRole(ctx, ["owner"]);

  const { tablesDB } = createAdminClient();
  const existing = (await tablesDB.getRow(
    DATABASE_ID,
    TABLES.savedCards,
    id,
  )) as unknown as SavedCard;
  if (existing.tenantId !== ctx.tenantId) throw new Error("Erişim engellendi.");

  await tablesDB.deleteRow(DATABASE_ID, TABLES.savedCards, id);

  await logAudit({
    tenantId: ctx.tenantId,
    userId: ctx.user.id,
    action: "delete",
    entityType: "saved_card",
    entityId: id,
    changes: { last4: existing.last4 },
  });

  revalidatePath("/settings/billing");
}
