import prisma from "../config/database";
import {
  generateProjectNumber,
  previewProjectNumber,
  releaseProjectNumber,
} from "./numbering.service";
import { NasFileManager } from "./nas-file-manager";
import type { CreateProjectInput } from "../schemas/projects.schema";

const nasFileManager = new NasFileManager();

const ALLOWED_SORT_FIELDS = [
  "id",
  "project_number",
  "name",
  "status",
  "created_at",
];

interface ListProjectsParams {
  page: number;
  limit: number;
  skip: number;
  sort: string;
  order: "asc" | "desc";
  search: string;
  status?: string;
  customer_id?: number;
}

export async function listProjects(params: ListProjectsParams) {
  const { page, limit, skip, sort, order, search, status, customer_id } =
    params;
  const sortField = ALLOWED_SORT_FIELDS.includes(sort) ? sort : "id";

  const where: Record<string, unknown> = {};
  if (status) where.status = status;
  if (customer_id) where.customer_id = customer_id;
  if (search)
    where.OR = [
      { name: { contains: search } },
      { project_number: { contains: search } },
    ];

  const [projects, total] = await Promise.all([
    prisma.projects.findMany({
      where,
      skip,
      take: limit,
      orderBy: { [sortField]: order },
      include: {
        customers: { select: { id: true, name: true } },
        users: { select: { id: true, first_name: true, last_name: true } },
        orders: { select: { order_number: true } },
      },
    }),
    prisma.projects.count({ where }),
  ]);

  const enriched = projects.map(({ customers, users, orders, ...p }) => ({
    ...p,
    customer_name: customers?.name || null,
    responsible_user_name: users
      ? `${users.first_name} ${users.last_name}`.trim()
      : null,
    order_number: orders?.order_number || null,
  }));

  return { data: enriched, total, page, limit };
}

export async function getProject(id: number) {
  const project = await prisma.projects.findUnique({
    where: { id },
    include: {
      customers: { select: { id: true, name: true } },
      users: { select: { id: true, first_name: true, last_name: true } },
      quotations: { select: { id: true, quotation_number: true } },
      orders: { select: { id: true, order_number: true, status: true } },
      project_notes: { orderBy: { created_at: "desc" } },
    },
  });
  if (!project) return null;
  const { orders, quotations, customers, users, ...rest } = project;
  return {
    ...rest,
    customer_name: customers?.name ?? null,
    responsible_user_name: users
      ? `${users.first_name} ${users.last_name}`
      : null,
    order_number: orders?.order_number ?? null,
    order_status: orders?.status ?? null,
    quotation_number: quotations?.quotation_number ?? null,
    has_nas_folder: project.project_number
      ? nasFileManager.projectFolderExists(project.project_number)
      : false,
  };
}

export async function updateProject(id: number, body: Record<string, any>) {
  const existing = await prisma.projects.findUnique({ where: { id } });
  if (!existing) return null;

  if (
    body.project_number !== undefined &&
    String(body.project_number) !== existing.project_number
  ) {
    return { error: "Číslo projektu nelze změnit", status: 400 };
  }

  const data: Record<string, unknown> = { modified_at: new Date() };
  const strFields = ["name", "status", "notes"];
  for (const f of strFields)
    if (body[f] !== undefined) data[f] = body[f] ? String(body[f]) : null;
  if (body.customer_id !== undefined)
    data.customer_id =
      body.customer_id != null ? Number(body.customer_id) : null;
  if (body.responsible_user_id !== undefined)
    data.responsible_user_id =
      body.responsible_user_id != null
        ? Number(body.responsible_user_id)
        : null;
  if (body.quotation_id !== undefined)
    data.quotation_id =
      body.quotation_id != null ? Number(body.quotation_id) : null;
  if (body.order_id !== undefined)
    data.order_id = body.order_id != null ? Number(body.order_id) : null;
  if (body.start_date !== undefined)
    data.start_date = body.start_date
      ? new Date(String(body.start_date))
      : null;
  if (body.end_date !== undefined)
    data.end_date = body.end_date ? new Date(String(body.end_date)) : null;

  const updated = await prisma.projects.update({ where: { id }, data });

  if (
    body.name !== undefined &&
    existing.name !== body.name &&
    existing.project_number &&
    nasFileManager.isConfigured()
  ) {
    const renamed = nasFileManager.renameProjectFolder(
      existing.project_number,
      String(body.name || ""),
    );
    if (!renamed) {
      console.error(
        "[projects.service] NAS folder not renamed for project",
        existing.project_number,
      );
    }
  }

  return updated;
}

/**
 * Create a standalone (manual) project. Takes the next SHARED number — the
 * same pool orders/projects draw from — generated atomically inside the
 * transaction (SELECT … FOR UPDATE via getNextSequence). order_id stays null,
 * which is what marks it "samostatný" in the UI. NAS folder creation is
 * best-effort (the manager self-guards isConfigured() and swallows fs errors).
 */
export async function createProject(data: CreateProjectInput) {
  if (data.customer_id != null) {
    const customer = await prisma.customers.findUnique({
      where: { id: data.customer_id },
    });
    if (!customer) return { error: "Zákazník nenalezen", status: 400 };
  }
  if (data.responsible_user_id != null) {
    const user = await prisma.users.findUnique({
      where: { id: data.responsible_user_id },
    });
    if (!user) return { error: "Zodpovědná osoba nenalezena", status: 400 };
  }

  const project = await prisma.$transaction(async (tx) => {
    const project_number = await generateProjectNumber(tx);
    return tx.projects.create({
      data: {
        project_number,
        name: data.name,
        customer_id: data.customer_id ?? null,
        responsible_user_id: data.responsible_user_id ?? null,
        status: data.status || "aktivni",
        start_date: data.start_date ? new Date(data.start_date) : null,
        end_date: data.end_date ? new Date(data.end_date) : null,
        notes: data.notes ?? null,
        order_id: null,
        quotation_id: null,
      },
    });
  });

  if (project.project_number && nasFileManager.isConfigured()) {
    const created = nasFileManager.createProjectFolder(
      project.project_number,
      project.name || "",
    );
    if (!created) {
      console.error(
        "[projects.service] NAS folder not created for project",
        project.project_number,
      );
    }
  }

  return project;
}

/** Preview the next project number for the create form (does NOT consume it). */
export async function getNextProjectNumber(): Promise<string> {
  return previewProjectNumber();
}

export async function deleteProject(id: number, deleteFiles: boolean = false) {
  const existing = await prisma.projects.findUnique({ where: { id } });
  if (!existing) return { error: "not_found" as const };
  if (existing.order_id) return { error: "has_order" as const };

  // Delete the DB row FIRST, then the NAS folder (mirrors orders.service
  // ordering). If the DB delete fails the folder is left untouched, so a DB
  // failure can't orphan the folder; conversely the NAS cleanup is best-effort
  // and non-fatal — a NAS error must not undo the committed DB delete.
  await prisma.projects.delete({ where: { id } });

  if (deleteFiles && existing.project_number && nasFileManager.isConfigured()) {
    const ok = await nasFileManager.deleteProjectFolder(
      existing.project_number,
    );
    if (!ok) {
      console.error(
        "[projects.service] NAS folder not deleted for project",
        existing.project_number,
      );
    }
  }

  const year = existing.created_at
    ? new Date(existing.created_at).getFullYear()
    : new Date().getFullYear();
  await releaseProjectNumber(year, existing.project_number ?? undefined);

  return existing;
}

export async function createProjectNote(
  projectId: number,
  data: {
    userId: number;
    firstName: string;
    lastName: string;
    content?: string;
  },
) {
  const project = await prisma.projects.findUnique({
    where: { id: projectId },
    select: { id: true },
  });
  if (!project) {
    return { error: "Projekt nenalezen" as const, status: 404 };
  }

  const note = await prisma.project_notes.create({
    data: {
      project_id: projectId,
      user_id: data.userId,
      user_name: `${data.firstName} ${data.lastName}`,
      content: data.content ? String(data.content) : null,
    },
  });
  return note;
}

export async function deleteProjectNote(projectId: number, noteId: number) {
  const note = await prisma.project_notes.findFirst({
    where: { id: noteId, project_id: projectId },
  });
  if (!note) return null;

  await prisma.project_notes.delete({ where: { id: noteId } });
  return note;
}
