"use server";

import { revalidatePath } from "next/cache";
import { and, eq, sql } from "drizzle-orm";
import { z } from "zod";
import { db } from "@/db";
import { territories, customers, users, auditLogs } from "@/db/schema";
import { requireSession } from "@/lib/auth";
import { canManageSettings } from "@/lib/rbac";
import { diffFields, writeAudit } from "@/lib/audit";
import { isUuid } from "@/lib/route-params";

/** Bốn cấp của cây khu vực. Chỉ dùng ở vị trí kiểu nên khai báo thẳng là kiểu,
 *  không cần mảng tồn tại lúc chạy. */
type Level = "REGION" | "PROVINCE" | "DISTRICT" | "WARD";

/**
 * Tên cấp để dựng thông báo. Không export: file `"use server"` chỉ được phép
 * export hàm async, export hằng số ở đây làm cả trang lỗi 500 khi tải.
 */
const LEVEL_LABEL: Record<string, string> = {
  REGION: "miền",
  PROVINCE: "tỉnh/thành",
  DISTRICT: "quận/huyện",
  WARD: "phường/xã",
};

/** Cấp con hợp lệ của mỗi cấp — cây khu vực phải đi tuần tự, không nhảy cấp. */
const CHILD_LEVEL: Record<string, Level | null> = {
  REGION: "PROVINCE",
  PROVINCE: "DISTRICT",
  DISTRICT: "WARD",
  WARD: null,
};

const territorySchema = z.object({
  name: z.string().trim().min(2, "Tên khu vực quá ngắn."),
  code: z.string().trim().min(1, "Mã khu vực không được để trống.").max(20),
  parentId: z.string().uuid().optional().or(z.literal("")),
});

export type TerritoryState = { error?: string; ok?: string };

export async function createTerritoryAction(
  _prev: TerritoryState,
  formData: FormData,
): Promise<TerritoryState> {
  const session = await requireSession();
  if (!canManageSettings(session)) return { error: "Bạn không có quyền sửa khu vực." };

  const parsed = territorySchema.safeParse({
    name: formData.get("name"),
    code: formData.get("code"),
    parentId: formData.get("parentId") || "",
  });

  if (!parsed.success) return { error: parsed.error.issues[0].message };
  const data = parsed.data;

  /* Cấp của khu vực mới suy ra từ cấp của khu vực cha, không cho người dùng chọn:
     chọn tay thì sớm muộn sẽ có phường nằm trực tiếp dưới miền, và mọi phép gộp
     dữ liệu theo cấp sau đó đều sai. */
  let level: Level = "REGION";

  if (data.parentId) {
    const [parent] = await db
      .select({ level: territories.level, name: territories.name })
      .from(territories)
      .where(and(eq(territories.tenantId, session.tenantId), eq(territories.id, data.parentId)))
      .limit(1);

    if (!parent) return { error: "Không tìm thấy khu vực cấp trên." };

    const childLevel = CHILD_LEVEL[parent.level];
    if (!childLevel) {
      return { error: `${parent.name} đã là cấp thấp nhất, không thêm được cấp con.` };
    }
    level = childLevel;
  }

  const [duplicate] = await db
    .select({ id: territories.id })
    .from(territories)
    .where(and(eq(territories.tenantId, session.tenantId), eq(territories.code, data.code)))
    .limit(1);

  if (duplicate) return { error: `Mã khu vực ${data.code} đã tồn tại.` };

  await db.insert(territories).values({
    tenantId: session.tenantId,
    code: data.code,
    name: data.name,
    level,
    parentId: data.parentId || null,
  });

  await db.insert(auditLogs).values({
    tenantId: session.tenantId,
    userId: session.userId,
    action: "CREATE",
    entityType: "territory",
    payload: { code: data.code, name: data.name, level },
  });

  revalidatePath("/danh-muc/khu-vuc");
  revalidatePath("/danh-muc");
  return { ok: `Đã thêm ${LEVEL_LABEL[level]} "${data.name}".` };
}

export async function renameTerritoryAction(formData: FormData): Promise<{ ok?: string; error?: string }> {
  const session = await requireSession();
  if (!canManageSettings(session)) return { error: "Bạn không có quyền sửa khu vực." };

  const id = String(formData.get("id") ?? "");
  const name = String(formData.get("name") ?? "").trim();
  if (!isUuid(id)) return { error: "Không tìm thấy khu vực." };
  if (name.length < 2) return { error: "Tên khu vực quá ngắn." };
  if (name.length > 120) return { error: "Tên khu vực tối đa 120 ký tự." };

  const [current] = await db
    .select({ name: territories.name, level: territories.level })
    .from(territories)
    .where(and(eq(territories.tenantId, session.tenantId), eq(territories.id, id)))
    .limit(1);
  if (!current) return { error: "Không tìm thấy khu vực." };
  if (current.name === name) return { ok: "Tên khu vực không đổi." };

  await db
    .update(territories)
    .set({ name })
    .where(and(eq(territories.tenantId, session.tenantId), eq(territories.id, id)));
  await writeAudit(session, "UPDATE", "territory", id, { name, changes: diffFields({ name: current.name }, { name }) });

  revalidatePath("/danh-muc/khu-vuc");
  return { ok: "Đã đổi tên." };
}

/**
 * Ngừng sử dụng một khu vực.
 *
 * Không xoá hẳn: đơn hàng và khách hàng cũ vẫn trỏ tới khu vực này, xoá đi thì
 * báo cáo lịch sử mất tên khu vực. Đánh dấu ngừng dùng thì nó biến khỏi các ô
 * chọn nhưng số liệu cũ vẫn đọc được.
 */
export async function toggleTerritoryActiveAction(formData: FormData): Promise<{ ok?: string; error?: string }> {
  const session = await requireSession();
  if (!canManageSettings(session)) return { error: "Bạn không có quyền sửa khu vực." };

  const id = String(formData.get("id") ?? "");
  if (!isUuid(id)) return { error: "Không tìm thấy khu vực." };

  const [target] = await db
    .select({ isActive: territories.isActive, name: territories.name })
    .from(territories)
    .where(and(eq(territories.tenantId, session.tenantId), eq(territories.id, id)))
    .limit(1);

  if (!target) return { error: "Không tìm thấy khu vực." };

  // Đang dùng mà muốn ngừng thì phải chắc không còn ai gắn vào.
  if (target.isActive) {
    const [{ customerCount }] = await db
      .select({ customerCount: sql<number>`count(*)::int` })
      .from(customers)
      .where(
        and(
          eq(customers.tenantId, session.tenantId),
          eq(customers.territoryId, id),
          eq(customers.isActive, true),
        ),
      );

    const [{ userCount }] = await db
      .select({ userCount: sql<number>`count(*)::int` })
      .from(users)
      .where(
        and(eq(users.tenantId, session.tenantId), eq(users.territoryId, id), eq(users.isActive, true)),
      );

    if (Number(customerCount) > 0 || Number(userCount) > 0) {
      return {
        error:
          `${target.name} còn ${customerCount} khách hàng và ${userCount} nhân sự đang gắn vào. ` +
          `Chuyển họ sang khu vực khác trước khi ngừng sử dụng.`,
      };
    }
  }

  await db
    .update(territories)
    .set({ isActive: !target.isActive })
    .where(and(eq(territories.tenantId, session.tenantId), eq(territories.id, id)));
  await writeAudit(session, "UPDATE", "territory", id, { name: target.name, changes: { isActive: { from: target.isActive, to: !target.isActive } } });

  revalidatePath("/danh-muc/khu-vuc");
  return { ok: target.isActive ? "Đã ngừng sử dụng khu vực." : "Đã dùng lại khu vực." };
}
