import type { Request, Response, NextFunction } from 'express';
import { z } from 'zod';
import { signupDespacho } from '../services/despacho.service.js';
import { AppError } from '../middlewares/error.middleware.js';
import { prisma } from '../config/database.js';
import { getPlanPrice } from '../services/payment/subscription.service.js';

const signupSchema = z.object({
  despacho: z.object({
    nombre: z.string().min(2, 'Nombre del despacho requerido'),
    regimenFiscal: z.string().optional(),
    codigoPostal: z.string().regex(/^\d{5}$/, 'Código postal inválido').optional(),
    verticalProfile: z.enum(['CONTABLE', 'JURIDICO', 'ARQUITECTURA']),
    // plan y frequency ya no se escogen en el registro — todos empiezan con trial genérico.
    // Se mantienen opcionales para compatibilidad backward con clientes antiguos.
    plan: z.enum(['trial', 'mi_empresa', 'mi_empresa_plus', 'business_control', 'business_cloud']).optional(),
    frequency: z.enum(['monthly', 'annual']).optional(),
  }),
  owner: z.object({
    nombre: z.string().min(2, 'Nombre del owner requerido'),
    email: z.string().email('Email inválido'),
    password: z.string().min(10, 'La contraseña debe tener al menos 10 caracteres'),
  }),
});

export async function getMyPlan(req: Request, res: Response, next: NextFunction) {
  try {
    const tenantId = req.user!.tenantId;
    const tenant = await prisma.tenant.findUnique({
      where: { id: tenantId },
      select: { dbMode: true, trialEndsAt: true, verticalProfile: true, plan: true },
    });

    if (!tenant) {
      return next(new AppError(404, 'Tenant no encontrado'));
    }

    const now = new Date();
    const isTrialActive = tenant.trialEndsAt ? tenant.trialEndsAt > now : false;

    // Mapea según trialEndsAt + tenant.plan (no dbMode). dbMode era proxy
    // antes de la introducción de Mi Empresa / Mi Empresa+ — para esos
    // planes, dbMode también es MANAGED y reportar `business_cloud` daba
    // mapeo equivocado. tenant.plan es la fuente de verdad post-migración
    // 20260426073942 (que añadió mi_empresa y mi_empresa_plus al enum).
    //
    // FIX: Si hay una subscription en trial con un plan específico (ej.
    // business_control desde una TrialInvitation), respetamos ese plan
    // para que el feature-gate y los límites funcionen correctamente.
    const subscription = await prisma.subscription.findFirst({
      where: { tenantId, status: { in: ['authorized', 'pending', 'paused', 'trial', 'trial_expired'] } },
      orderBy: { createdAt: 'desc' },
      select: {
        status: true, amount: true, plan: true,
        currentPeriodStart: true, currentPeriodEnd: true,
      },
    });

    let currentPlan: string;
    if (subscription?.status === 'trial' && subscription.plan && subscription.plan !== 'trial') {
      currentPlan = subscription.plan;
    } else if (isTrialActive) {
      currentPlan = 'trial';
    } else {
      currentPlan = String(tenant.plan);
    }

    // Precio de catálogo del plan actual (primer año, anual). La UI lo usa
    // cuando la suscripción aún no tiene monto (trial/trial_expired) para
    // mostrar el CTA de pago.
    let planPrice: number | null = null;
    if (currentPlan && currentPlan !== 'trial' && currentPlan !== 'custom') {
      try {
        planPrice = await getPlanPrice(currentPlan as any, 'annual', 'firstYear');
      } catch {
        planPrice = null;
      }
    }

    // Estado de suscripción activa (si hay) — alimenta la UI con el monto
    // recurrente actual, fecha de próxima renovación y si el primer pago
    // (cuando aplica dualidad firstYear) ya fue completado.
    return res.json({
      plan: currentPlan,
      dbMode: tenant.dbMode,
      trialEndsAt: tenant.trialEndsAt?.toISOString() ?? null,
      isTrialActive,
      planPrice,
      subscription: subscription
        ? {
            status: subscription.status,
            plan: subscription.plan,
            amount: Number(subscription.amount),
            currentPeriodStart: subscription.currentPeriodStart?.toISOString() ?? null,
            currentPeriodEnd: subscription.currentPeriodEnd?.toISOString() ?? null,
          }
        : null,
    });
  } catch (error) {
    return next(error);
  }
}

export async function signup(req: Request, res: Response, next: NextFunction) {
  try {
    const data = signupSchema.parse(req.body);
    const result = await signupDespacho(data);
    return res.status(201).json(result);
  } catch (error: any) {
    if (error instanceof z.ZodError) {
      return next(new AppError(400, error.errors[0].message));
    }
    if (error.message?.includes('Ya existe')) {
      return next(new AppError(409, error.message));
    }
    return next(error);
  }
}
