"use server";

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

import { logAudit } from "./audit";
import { DATABASE_ID, TABLES, type Prosthetic } from "./schema";
import { createAdminClient } from "./server";
import { requireRole, requireTenant, requireTenantKind } from "./tenant-guard";
import type { ProstheticActionState, ProstheticFormState } from "./prosthetic-types";
import { prostheticSchema } from "@/lib/validation/prosthetic";

function appwriteError(e: unknown, fallback = "Beklenmeyen bir hata oluştu."): string {
  if (e instanceof AppwriteException) return e.message || fallback;
  return process.env.NODE_ENV !== "production" && e instanceof Error
    ? `${fallback} (${e.message})`
    : fallback;
}

function flattenErrors(err: z.ZodError): Record<string, string> {
  const out: Record<string, string> = {};
  for (const issue of err.issues) {
    const key = issue.path.join(".");
    if (key && !out[key]) out[key] = issue.message;
  }
  return out;
}

function pickFields(formData: FormData) {
  return {
    name: String(formData.get("name") ?? "").trim(),
    type: String(formData.get("type") ?? "").trim(),
    unitPrice: String(formData.get("unitPrice") ?? "0"),
    currency: String(formData.get("currency") ?? "").trim(),
  };
}

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

export async function createProstheticAction(
  _prev: ProstheticFormState,
  formData: FormData,
): Promise<ProstheticFormState> {
  let ctx;
  try {
    ctx = await requireTenant();
    requireRole(ctx, ["owner", "admin", "member"]);
    requireTenantKind(ctx, ["lab"]);
  } catch {
    return { ok: false, error: "Bu işlem yalnızca laboratuvar hesaplarında yapılabilir." };
  }

  const parsed = prostheticSchema.safeParse(pickFields(formData));
  if (!parsed.success) {
    return { ok: false, error: "Form geçersiz.", fieldErrors: flattenErrors(parsed.error) };
  }

  try {
    const { tablesDB } = createAdminClient();
    const created = await tablesDB.createRow(
      DATABASE_ID,
      TABLES.prosthetics,
      ID.unique(),
      {
        tenantId: ctx.tenantId,
        createdBy: ctx.user.id,
        name: parsed.data.name,
        type: parsed.data.type,
        unitPrice: parsed.data.unitPrice,
        currency: parsed.data.currency,
        archived: false,
      },
      prostheticPermissions(ctx.tenantId),
    );
    await logAudit({
      tenantId: ctx.tenantId,
      userId: ctx.user.id,
      action: "create",
      entityType: "prosthetic",
      entityId: created.$id,
      changes: parsed.data,
    });
  } catch (e) {
    return { ok: false, error: appwriteError(e, "Ürün eklenemedi.") };
  }

  revalidatePath("/products");
  return { ok: true };
}

export async function updateProstheticAction(
  _prev: ProstheticFormState,
  formData: FormData,
): Promise<ProstheticFormState> {
  const id = String(formData.get("id") ?? "").trim();
  if (!id) return { ok: false, error: "Ürün bulunamadı." };

  let ctx;
  try {
    ctx = await requireTenant();
    requireRole(ctx, ["owner", "admin", "member"]);
    requireTenantKind(ctx, ["lab"]);
  } catch {
    return { ok: false, error: "Bu işlem yalnızca laboratuvar hesaplarında yapılabilir." };
  }

  const parsed = prostheticSchema.safeParse(pickFields(formData));
  if (!parsed.success) {
    return { ok: false, error: "Form geçersiz.", fieldErrors: flattenErrors(parsed.error) };
  }

  try {
    const { tablesDB } = createAdminClient();
    const row = (await tablesDB.getRow(
      DATABASE_ID,
      TABLES.prosthetics,
      id,
    )) as unknown as Prosthetic;
    if (row.tenantId !== ctx.tenantId) {
      return { ok: false, error: "Bu ürünü düzenleme yetkiniz yok." };
    }
    await tablesDB.updateRow(DATABASE_ID, TABLES.prosthetics, id, {
      name: parsed.data.name,
      type: parsed.data.type,
      unitPrice: parsed.data.unitPrice,
      currency: parsed.data.currency,
    });
    await logAudit({
      tenantId: ctx.tenantId,
      userId: ctx.user.id,
      action: "update",
      entityType: "prosthetic",
      entityId: id,
      changes: parsed.data,
    });
  } catch (e) {
    return { ok: false, error: appwriteError(e, "Güncellenemedi.") };
  }

  revalidatePath("/products");
  return { ok: true };
}

export async function archiveProstheticAction(
  _prev: ProstheticActionState,
  formData: FormData,
): Promise<ProstheticActionState> {
  const id = String(formData.get("id") ?? "").trim();
  if (!id) return { ok: false, error: "Ürün bulunamadı." };

  let ctx;
  try {
    ctx = await requireTenant();
    requireRole(ctx, ["owner", "admin"]);
    requireTenantKind(ctx, ["lab"]);
  } catch {
    return { ok: false, error: "Bu işlem için yetkiniz yok." };
  }

  try {
    const { tablesDB } = createAdminClient();
    const row = (await tablesDB.getRow(
      DATABASE_ID,
      TABLES.prosthetics,
      id,
    )) as unknown as Prosthetic;
    if (row.tenantId !== ctx.tenantId) {
      return { ok: false, error: "Bu ürünü düzenleme yetkiniz yok." };
    }
    await tablesDB.updateRow(DATABASE_ID, TABLES.prosthetics, id, {
      archived: !row.archived,
    });
    await logAudit({
      tenantId: ctx.tenantId,
      userId: ctx.user.id,
      action: "update",
      entityType: "prosthetic",
      entityId: id,
      changes: { archived: !row.archived },
    });
  } catch (e) {
    return { ok: false, error: appwriteError(e, "İşlem başarısız.") };
  }

  revalidatePath("/products");
  return { ok: true };
}

export async function deleteProstheticAction(
  _prev: ProstheticActionState,
  formData: FormData,
): Promise<ProstheticActionState> {
  const id = String(formData.get("id") ?? "").trim();
  if (!id) return { ok: false, error: "Ürün bulunamadı." };

  let ctx;
  try {
    ctx = await requireTenant();
    requireRole(ctx, ["owner", "admin"]);
    requireTenantKind(ctx, ["lab"]);
  } catch {
    return { ok: false, error: "Bu işlem için yetkiniz yok." };
  }

  try {
    const { tablesDB } = createAdminClient();
    const row = (await tablesDB.getRow(
      DATABASE_ID,
      TABLES.prosthetics,
      id,
    )) as unknown as Prosthetic;
    if (row.tenantId !== ctx.tenantId) {
      return { ok: false, error: "Bu ürünü silme yetkiniz yok." };
    }
    await tablesDB.deleteRow(DATABASE_ID, TABLES.prosthetics, id);
    await logAudit({
      tenantId: ctx.tenantId,
      userId: ctx.user.id,
      action: "delete",
      entityType: "prosthetic",
      entityId: id,
    });
  } catch (e) {
    return { ok: false, error: appwriteError(e, "Silinemedi.") };
  }

  revalidatePath("/products");
  return { ok: true };
}
