"use server";

import { db } from "@/db";
import { services, tags } from "@/db/schema";
import { revalidatePath } from "next/cache";
import { eq, and } from "drizzle-orm";
import { z } from "zod";
import { getServerSession } from "next-auth";
import { authOptions } from "@/lib/auth";
import { addPoolValue, renamePoolValue } from "@/lib/taxonomy";

const serviceSchema = z.object({
  name: z.string().min(1, "Nome richiesto"),
  description: z.string().optional(),
  unit_price: z.coerce.number().min(0.01, "Prezzo deve essere maggiore di 0"),
  category: z.string().optional(),
});

async function requireAdmin() {
  const session = await getServerSession(authOptions);
  if (!session) throw new Error("Non autorizzato");
}

export async function createService(formData: FormData) {
  await requireAdmin();
  const parsed = serviceSchema.safeParse({
    name: formData.get("name"),
    description: formData.get("description") ?? "",
    unit_price: formData.get("unit_price"),
    category: formData.get("category") ?? "",
  });
  if (!parsed.success) throw new Error(parsed.error.issues[0].message);
  // New rows created from /admin/catalog are NOT migrated — migrated_from/migrated_id stay null
  await db.insert(services).values({
    name: parsed.data.name,
    description: parsed.data.description ?? null,
    unit_price: parsed.data.unit_price.toFixed(2),
    category: parsed.data.category || null,
  });
  revalidatePath("/admin/catalog");
}

export async function updateService(serviceId: string, formData: FormData) {
  await requireAdmin();
  const parsed = serviceSchema.safeParse({
    name: formData.get("name"),
    description: formData.get("description") ?? "",
    unit_price: formData.get("unit_price"),
    category: formData.get("category") ?? "",
  });
  if (!parsed.success) throw new Error(parsed.error.issues[0].message);
  await db
    .update(services)
    .set({
      name: parsed.data.name,
      description: parsed.data.description ?? null,
      unit_price: parsed.data.unit_price.toFixed(2),
      category: parsed.data.category || null,
    })
    .where(eq(services.id, serviceId));
  revalidatePath("/admin/catalog");
}

export async function toggleServiceActive(serviceId: string, active: boolean) {
  await requireAdmin();
  await db.update(services).set({ active }).where(eq(services.id, serviceId));
  revalidatePath("/admin/catalog");
}

// ── Inline-edit, tag, and quick-add actions (Phase 11 database-view) ────────

const EDITABLE_FIELDS = ["name", "description", "category", "fase", "unit_price", "active"] as const;
type EditableField = (typeof EDITABLE_FIELDS)[number];

export async function updateServiceField(
  serviceId: string,
  fieldName: EditableField,
  value: string | boolean
) {
  await requireAdmin();

  if (!EDITABLE_FIELDS.includes(fieldName)) {
    throw new Error(`Campo non editabile: ${fieldName}`);
  }

  if (fieldName === "name") {
    const s = String(value).trim();
    if (s.length === 0) throw new Error("Nome richiesto");
    await db.update(services).set({ name: s }).where(eq(services.id, serviceId));
  } else if (fieldName === "description") {
    const s = String(value).trim();
    await db.update(services).set({ description: s || null }).where(eq(services.id, serviceId));
  } else if (fieldName === "category") {
    const s = String(value).trim();
    await db.update(services).set({ category: s || null }).where(eq(services.id, serviceId));
  } else if (fieldName === "fase") {
    const s = String(value).trim();
    await db.update(services).set({ fase: s || null }).where(eq(services.id, serviceId));
    if (s) await addPoolValue("service_fase", s);
  } else if (fieldName === "unit_price") {
    // Normalize locale-formatted input (WR-04): the cell displays it-IT (€1.234,50),
    // so an admin may type "1.234,50". When a comma is present, treat "." as thousands
    // separators and "," as the decimal mark; otherwise parse "." as the decimal mark.
    // Number() (not parseFloat) rejects trailing garbage like "12abc".
    const rawInput = String(value).trim();
    const normalized = rawInput.includes(",")
      ? rawInput.replace(/\./g, "").replace(",", ".")
      : rawInput;
    const num = Number(normalized);
    if (!Number.isFinite(num) || num < 0) throw new Error("Prezzo invalido");
    await db.update(services).set({ unit_price: num.toFixed(2) }).where(eq(services.id, serviceId));
  } else if (fieldName === "active") {
    const boolValue = typeof value === "boolean" ? value : value === "true";
    await db.update(services).set({ active: boolValue }).where(eq(services.id, serviceId));
  }

  revalidatePath("/admin/catalog");
}

// ── Multi-select option fields (Notion-style shared pools) ──────────────────
// "tag" and "pacchetto" are stored in the polymorphic `tags` table, scoped by
// entity_type so the two pools stay separate.

const MULTI_ENTITY: Record<MultiSelectField, string> = {
  tag: "services",
  pacchetto: "services.pacchetto",
};
const MULTI_FIELDS = ["tag", "pacchetto"] as const;
export type MultiSelectField = (typeof MULTI_FIELDS)[number];

type SingleSelectField = "categoria" | "fase";

export async function addServiceOption(
  field: MultiSelectField,
  serviceId: string,
  value: string
) {
  await requireAdmin();
  if (!MULTI_FIELDS.includes(field)) throw new Error(`Campo non valido: ${field}`);
  const trimmed = value.trim();
  if (trimmed.length === 0) throw new Error("Valore richiesto");

  await db
    .insert(tags)
    .values({ entity_type: MULTI_ENTITY[field], entity_id: serviceId, name: trimmed })
    .onConflictDoNothing();

  // Register into the persistent pool so it survives unassignment / shows in settings.
  await addPoolValue(field === "tag" ? "service_offerta" : "service_pacchetto", trimmed);

  revalidatePath("/admin/catalog");
}

export async function removeServiceOption(
  field: MultiSelectField,
  serviceId: string,
  value: string
) {
  await requireAdmin();
  if (!MULTI_FIELDS.includes(field)) throw new Error(`Campo non valido: ${field}`);

  await db
    .delete(tags)
    .where(
      and(
        eq(tags.entity_type, MULTI_ENTITY[field]),
        eq(tags.entity_id, serviceId),
        eq(tags.name, value)
      )
    );

  revalidatePath("/admin/catalog");
}

// ── Rename an option everywhere it is used (propagates across all services) ───
// Works for both multi-select pools (tag/pacchetto) and single-select columns
// (categoria/fase). This is what makes the dropdown options feel persistent &
// editable like Notion select properties.

export async function renameServiceOption(
  field: MultiSelectField | SingleSelectField,
  oldValue: string,
  newValue: string
) {
  await requireAdmin();
  const next = newValue.trim();
  if (next.length === 0) throw new Error("Nuovo nome richiesto");
  if (next === oldValue) return;

  if (field === "tag" || field === "pacchetto") {
    await db
      .update(tags)
      .set({ name: next })
      .where(and(eq(tags.entity_type, MULTI_ENTITY[field]), eq(tags.name, oldValue)));
    await renamePoolValue(field === "tag" ? "service_offerta" : "service_pacchetto", oldValue, next);
  } else if (field === "categoria") {
    await db.update(services).set({ category: next }).where(eq(services.category, oldValue));
  } else if (field === "fase") {
    await db.update(services).set({ fase: next }).where(eq(services.fase, oldValue));
    await renamePoolValue("service_fase", oldValue, next);
  } else {
    throw new Error(`Campo non valido: ${field}`);
  }

  revalidatePath("/admin/catalog");
}

// ── Quick-add: create a service from the bottom row with all scalar fields set
// and active=true in one Enter. Tags/pacchetto are assigned afterwards (they
// need the new row's id). Only `name` is required.

export type QuickAddPayload = {
  name: string;
  description?: string;
  category?: string;
  fase?: string;
  unit_price?: string;
};

export async function quickAddService(payload: QuickAddPayload | string) {
  await requireAdmin();
  // Back-compat: accept a bare name string.
  const data: QuickAddPayload = typeof payload === "string" ? { name: payload } : payload;

  const name = data.name.trim();
  if (name.length === 0) throw new Error("Nome richiesto");

  let unit_price = "0.00";
  if (data.unit_price && data.unit_price.trim().length > 0) {
    const raw = data.unit_price.trim();
    const normalized = raw.includes(",") ? raw.replace(/\./g, "").replace(",", ".") : raw;
    const num = Number(normalized);
    if (!Number.isFinite(num) || num < 0) throw new Error("Prezzo invalido");
    unit_price = num.toFixed(2);
  }

  const fase = data.fase?.trim() || null;
  await db.insert(services).values({
    name,
    description: data.description?.trim() || null,
    category: data.category?.trim() || null,
    fase,
    unit_price,
    active: true,
  });
  if (fase) await addPoolValue("service_fase", fase);

  revalidatePath("/admin/catalog");
}
