"use server";
import { db } from '@/lib/db';
import { user, inscripcion, curso, colegio, notificacion } from '@/db/schema';
import { eq, count } from 'drizzle-orm';
import { revalidatePath } from "next/cache";
import { authOptions } from "@/lib/auth";
import { getServerSession } from "next-auth";
import crypto from "crypto";

const PATH = "/dashboard/usuarios";

async function validateTenantAccess(userId: string) {
  const session = await getServerSession(authOptions);
  if (!session) throw new Error("No autenticado");

  if (session.user.role === "SUPERADMIN") return session;

  if (session.user.role === "ADMIN_COLEGIO") {
    const targetUser = await db.query.user.findFirst({
      where: eq(user.id, userId),
      columns: { colegioId: true }
    });
    if (!targetUser || targetUser.colegioId !== session.user.colegioId) {
      throw new Error("No autorizado para este colegio");
    }
    return session;
  }

  throw new Error("No autorizado");
}

export async function toggleUserStatus(id: string, currentStatus: string) {
  try {
    await validateTenantAccess(id);
    const newStatus = currentStatus === "SOLVENTE" ? "MOROSO" : "SOLVENTE";
    await db.update(user)
      .set({ status: newStatus as any, updatedAt: new Date() })
      .where(eq(user.id, id));
    revalidatePath(PATH);
    return { success: true };
  } catch (error: any) {
    return { success: false, error: error.message || "No se pudo actualizar el estado." };
  }
}

export async function createUsuario(formData: FormData) {
  const session = await getServerSession(authOptions);
  if (!session || (session.user.role !== "SUPERADMIN" && session.user.role !== "ADMIN_COLEGIO")) {
    return { success: false, error: "No autorizado" };
  }

  const name                 = (formData.get("name") as string) || null;
  const email                = formData.get("email") as string;
  const telefono             = (formData.get("telefono") as string) || null;
  const direccion            = (formData.get("direccion") as string) || null;
  const observaciones        = (formData.get("observaciones") as string) || null;
  const representanteNombre  = (formData.get("representanteNombre") as string) || null;
  const representanteTelefono= (formData.get("representanteTelefono") as string) || null;
  const role                 = (formData.get("role") as string) || "ESTUDIANTE";
  const status               = (formData.get("status") as string) || "SOLVENTE";
  const password             = (formData.get("password") as string) || "Nirgua2024";
  const edadStr              = formData.get("edad") as string;
  const edad                 = edadStr ? parseInt(edadStr) : null;
  const cursoIds             = formData.getAll("cursoId") as string[];
  const requestedColegioId   = formData.get("colegioId") as string | null;

  // Multi-tenant isolation for creation
  let colegioId: string | null = null;
  if (session.user.role === "SUPERADMIN") {
    colegioId = requestedColegioId && requestedColegioId !== "" ? requestedColegioId : null;
  } else {
    colegioId = session.user.colegioId as string;
  }

  try {
    const bcrypt = await import("bcryptjs");
    const hashed = await bcrypt.hash(password, 10);
    const newUserId = crypto.randomUUID();

    await db.insert(user).values({
      id: newUserId,
      name,
      email,
      password: hashed,
      role: role as any,
      status: status as any,
      telefono,
      direccion,
      observaciones,
      representanteNombre,
      representanteTelefono,
      edad,
      colegioId,
      updatedAt: new Date()
    });

    if (cursoIds.length > 0) {
      for (const cId of cursoIds) {
        // Enforce that if admin is ADMIN_COLEGIO, they can only enroll in courses of their college
        if (session.user.role === "ADMIN_COLEGIO") {
          const course = await db.query.curso.findFirst({
            where: eq(curso.id, cId),
            columns: { colegioId: true }
          });
          if (course?.colegioId !== session.user.colegioId) continue;
        }

        await db.insert(inscripcion).values({
          id: crypto.randomUUID(),
          userId: newUserId,
          cursoId: cId,
          estadoFlujo: "INSCRITO",
          estadoPago: "APROBADO",
          updatedAt: new Date()
        });
      }
    }

    // Crear notificación
    await db.insert(notificacion).values({
      id: crypto.randomUUID(),
      titulo: "Nuevo Usuario Registrado",
      mensaje: `Se ha registrado al usuario ${name || email} con el rol ${role}. El usuario y la clave han sido enviados a su correo y al del registrante.`,
      colegioId: colegioId,
    });

    try {
      const nodemailer = require("nodemailer");
      const transporter = nodemailer.createTransport({
        host: process.env.SMTP_HOST || "localhost",
        port: Number(process.env.SMTP_PORT) || 25,
        secure: process.env.SMTP_SECURE === "true",
        auth: process.env.SMTP_USER ? {
          user: process.env.SMTP_USER,
          pass: process.env.SMTP_PASS,
        } : undefined,
        tls: { rejectUnauthorized: false }
      });

      // Obtener correos de SuperAdmin
      const superAdmins = await db.query.user.findMany({
        where: eq(user.role, "SUPERADMIN"),
        columns: { email: true }
      });
      const superAdminEmails = superAdmins.map(u => u.email);

      // Obtener correo del Colegio
      let colegioEmail: string | null = null;
      let colegioNombre = "Nuestra Institución";
      if (colegioId) {
        const col = await db.query.colegio.findFirst({
          where: eq(colegio.id, colegioId),
          columns: { email: true, nombre: true }
        });
        if (col) {
          colegioEmail = col.email;
          colegioNombre = col.nombre;
        }
      }

      const recipients = new Set([email]); // Usuario que se registra
      if (session.user.email) recipients.add(session.user.email); // Registrante
      superAdminEmails.forEach(e => { if (e) recipients.add(e); }); // SuperAdmins

      if ((role === "ESTUDIANTE" || role === "PROFESOR") && colegioEmail) {
        recipients.add(colegioEmail); // Correo del colegio
      }

      const mailOptions = {
        from: `"Cursos Nirgua" <info@cursos.nirgua.com.ve>`,
        to: Array.from(recipients).join(", "),
        subject: `Registro Exitoso: Bienvenido a ${colegioNombre}`,
        html: `
          <div style="font-family: sans-serif; color: #333; max-width: 600px; border: 1px solid #eee; padding: 20px; border-radius: 10px;">
            <h2 style="color: #43a047;">¡Bienvenido a ${colegioNombre}!</h2>
            <p>Se ha creado un usuario para ti en nuestra plataforma con el rol de ${role}.</p>
            <hr style="border: 0; border-top: 1px solid #eee;" />
            <p><strong>URL de Acceso:</strong> <a href="https://cursos.nirgua.com.ve/signin">https://cursos.nirgua.com.ve/signin</a></p>
            <p><strong>Usuario / Correo:</strong> ${email}</p>
            <p><strong>Contraseña:</strong> ${password}</p>
            <p style="font-size: 12px; color: #999; margin-top: 20px;">
              Este es un correo automático generado por el sistema de Cursos Nirgua.
            </p>
          </div>
        `,
      };

      await transporter.sendMail(mailOptions);
    } catch (mailError) {
      console.error("Error enviando el correo:", mailError);
    }

    revalidatePath(PATH);
    return { success: true };
  } catch (e: any) {
    console.error("Error in createUsuario:", e);
    // Handle duplicate entry errors (MySQL error code 1062)
    if (e.code === 'ER_DUP_ENTRY' || e.errno === 1062) {
      return { success: false, error: "El correo o cédula ya existe en el sistema." };
    }
    return { success: false, error: e.message || "Hubo un error al registrar el usuario." };
  }
}

export async function updateUsuario(id: string, formData: FormData) {
  try {
    const session = await validateTenantAccess(id);

    const name                 = (formData.get("name") as string) || null;
    const email                = formData.get("email") as string;
    const telefono             = (formData.get("telefono") as string) || null;
    const direccion            = (formData.get("direccion") as string) || null;
    const observaciones        = (formData.get("observaciones") as string) || null;
    const representanteNombre  = (formData.get("representanteNombre") as string) || null;
    const representanteTelefono= (formData.get("representanteTelefono") as string) || null;
    const role                 = (formData.get("role") as string) || "ESTUDIANTE";
    const status               = (formData.get("status") as string) || "SOLVENTE";
    const edadStr              = formData.get("edad") as string;
    const edad                 = edadStr ? parseInt(edadStr) : null;
    const cursoIds             = formData.getAll("cursoId") as string[];
    const requestedColegioId   = formData.get("colegioId") as string | null;
    const password             = formData.get("password") as string | null;

    const dataToUpdate: any = {
      name, email, role: role as any, status: status as any,
      telefono, direccion, observaciones, representanteNombre, representanteTelefono, edad,
      updatedAt: new Date()
    };

    // Only SUPERADMIN can change a user's college
    if (session.user.role === "SUPERADMIN" && requestedColegioId !== undefined) {
      dataToUpdate.colegioId = (requestedColegioId && requestedColegioId !== "") ? requestedColegioId : null;
    }

    if (password && password.trim() !== "") {
      const bcrypt = await import("bcryptjs");
      dataToUpdate.password = await bcrypt.hash(password, 10);
    }

    await db.update(user)
      .set(dataToUpdate)
      .where(eq(user.id, id));

    // Delete and re-create inscriptions
    await db.delete(inscripcion).where(eq(inscripcion.userId, id));

    if (cursoIds.length > 0) {
      for (const cId of cursoIds) {
        // Enforce tenant check for enrollment
        if (session.user.role === "ADMIN_COLEGIO") {
          const course = await db.query.curso.findFirst({
            where: eq(curso.id, cId),
            columns: { colegioId: true }
          });
          if (course?.colegioId !== session.user.colegioId) continue;
        }

        await db.insert(inscripcion).values({
          id: crypto.randomUUID(),
          userId: id,
          cursoId: cId,
          estadoFlujo: "INSCRITO",
          estadoPago: "APROBADO",
          updatedAt: new Date()
        });
      }
    }

    revalidatePath(PATH);
    return { success: true };
  } catch (e: any) {
    return { success: false, error: e.message || "Error al actualizar el usuario." };
  }
}

export async function deleteUsuario(id: string) {
  try {
    await validateTenantAccess(id);
    const [countRes] = await db.select({ value: count() }).from(inscripcion).where(eq(inscripcion.userId, id));
    if (countRes.value > 0) {
      return { success: false, error: "No se puede eliminar: el usuario tiene inscripciones activas." };
    }
    // Soft delete
    await db.update(user)
      .set({ activo: false, updatedAt: new Date() })
      .where(eq(user.id, id));
    revalidatePath(PATH);
    return { success: true };
  } catch (error: any) {
    return { success: false, error: error.message || "Error al eliminar el usuario." };
  }
}
