import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { partnersService, CreatePartnerDto, UpdatePartnerDto, PartnerFilters } from './partners.service.js';
import { ApiResponse, AuthenticatedRequest, ValidationError } from '../../shared/types/index.js';

// Validation schemas (accept both snake_case and camelCase from frontend)
const createPartnerSchema = z.object({
  name: z.string().min(1, 'El nombre es requerido').max(255),
  legal_name: z.string().max(255).optional(),
  legalName: z.string().max(255).optional(),
  partner_type: z.enum(['person', 'company']).default('person'),
  partnerType: z.enum(['person', 'company']).default('person'),
  is_customer: z.boolean().default(false),
  isCustomer: z.boolean().default(false),
  is_supplier: z.boolean().default(false),
  isSupplier: z.boolean().default(false),
  is_employee: z.boolean().default(false),
  isEmployee: z.boolean().default(false),
  is_company: z.boolean().default(false),
  isCompany: z.boolean().default(false),
  email: z.string().email('Email inválido').max(255).optional(),
  phone: z.string().max(50).optional(),
  mobile: z.string().max(50).optional(),
  website: z.string().url('URL inválida').max(255).optional(),
  tax_id: z.string().max(50).optional(),
  taxId: z.string().max(50).optional(),
  company_id: z.string().uuid().optional(),
  companyId: z.string().uuid().optional(),
  parent_id: z.string().uuid().optional(),
  parentId: z.string().uuid().optional(),
  currency_id: z.string().uuid().optional(),
  currencyId: z.string().uuid().optional(),
  notes: z.string().optional(),
});

const updatePartnerSchema = z.object({
  name: z.string().min(1).max(255).optional(),
  legal_name: z.string().max(255).optional().nullable(),
  legalName: z.string().max(255).optional().nullable(),
  is_customer: z.boolean().optional(),
  isCustomer: z.boolean().optional(),
  is_supplier: z.boolean().optional(),
  isSupplier: z.boolean().optional(),
  is_employee: z.boolean().optional(),
  isEmployee: z.boolean().optional(),
  email: z.string().email('Email inválido').max(255).optional().nullable(),
  phone: z.string().max(50).optional().nullable(),
  mobile: z.string().max(50).optional().nullable(),
  website: z.string().url('URL inválida').max(255).optional().nullable(),
  tax_id: z.string().max(50).optional().nullable(),
  taxId: z.string().max(50).optional().nullable(),
  company_id: z.string().uuid().optional().nullable(),
  companyId: z.string().uuid().optional().nullable(),
  parent_id: z.string().uuid().optional().nullable(),
  parentId: z.string().uuid().optional().nullable(),
  currency_id: z.string().uuid().optional().nullable(),
  currencyId: z.string().uuid().optional().nullable(),
  notes: z.string().optional().nullable(),
  active: z.boolean().optional(),
});

const querySchema = z.object({
  search: z.string().optional(),
  is_customer: z.coerce.boolean().optional(),
  isCustomer: z.coerce.boolean().optional(),
  is_supplier: z.coerce.boolean().optional(),
  isSupplier: z.coerce.boolean().optional(),
  is_employee: z.coerce.boolean().optional(),
  isEmployee: z.coerce.boolean().optional(),
  company_id: z.string().uuid().optional(),
  companyId: z.string().uuid().optional(),
  active: z.coerce.boolean().optional(),
  page: z.coerce.number().int().positive().default(1),
  limit: z.coerce.number().int().positive().max(100).default(20),
});

class PartnersController {
  async findAll(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = querySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }

      const data = queryResult.data;
      const tenantId = req.user!.tenantId;
      const filters: PartnerFilters = {
        search: data.search,
        isCustomer: data.isCustomer ?? data.is_customer,
        isSupplier: data.isSupplier ?? data.is_supplier,
        isEmployee: data.isEmployee ?? data.is_employee,
        companyId: data.companyId || data.company_id,
        active: data.active,
        page: data.page,
        limit: data.limit,
      };

      const result = await partnersService.findAll(tenantId, filters);

      const response: ApiResponse = {
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: filters.page || 1,
          limit: filters.limit || 20,
          totalPages: Math.ceil(result.total / (filters.limit || 20)),
        },
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async findCustomers(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = querySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }

      const data = queryResult.data;
      const tenantId = req.user!.tenantId;
      const filters = {
        search: data.search,
        isEmployee: data.isEmployee ?? data.is_employee,
        companyId: data.companyId || data.company_id,
        active: data.active,
        page: data.page,
        limit: data.limit,
      };

      const result = await partnersService.findCustomers(tenantId, filters);

      const response: ApiResponse = {
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: filters.page || 1,
          limit: filters.limit || 20,
          totalPages: Math.ceil(result.total / (filters.limit || 20)),
        },
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async findSuppliers(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const queryResult = querySchema.safeParse(req.query);
      if (!queryResult.success) {
        throw new ValidationError('Parámetros de consulta inválidos', queryResult.error.errors);
      }

      const data = queryResult.data;
      const tenantId = req.user!.tenantId;
      const filters = {
        search: data.search,
        isEmployee: data.isEmployee ?? data.is_employee,
        companyId: data.companyId || data.company_id,
        active: data.active,
        page: data.page,
        limit: data.limit,
      };

      const result = await partnersService.findSuppliers(tenantId, filters);

      const response: ApiResponse = {
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: filters.page || 1,
          limit: filters.limit || 20,
          totalPages: Math.ceil(result.total / (filters.limit || 20)),
        },
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async findById(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const tenantId = req.user!.tenantId;
      const partner = await partnersService.findById(id, tenantId);

      const response: ApiResponse = {
        success: true,
        data: partner,
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async create(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const parseResult = createPartnerSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de contacto inválidos', parseResult.error.errors);
      }

      const data = parseResult.data;
      const tenantId = req.user!.tenantId;
      const userId = req.user!.userId;

      // Transform to camelCase DTO
      const dto: CreatePartnerDto = {
        name: data.name,
        legalName: data.legalName || data.legal_name,
        partnerType: data.partnerType || data.partner_type,
        isCustomer: data.isCustomer ?? data.is_customer,
        isSupplier: data.isSupplier ?? data.is_supplier,
        isEmployee: data.isEmployee ?? data.is_employee,
        isCompany: data.isCompany ?? data.is_company,
        email: data.email,
        phone: data.phone,
        mobile: data.mobile,
        website: data.website,
        taxId: data.taxId || data.tax_id,
        companyId: data.companyId || data.company_id,
        parentId: data.parentId || data.parent_id,
        currencyId: data.currencyId || data.currency_id,
        notes: data.notes,
      };

      const partner = await partnersService.create(dto, tenantId, userId);

      const response: ApiResponse = {
        success: true,
        data: partner,
        message: 'Contacto creado exitosamente',
      };

      res.status(201).json(response);
    } catch (error) {
      next(error);
    }
  }

  async update(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const parseResult = updatePartnerSchema.safeParse(req.body);
      if (!parseResult.success) {
        throw new ValidationError('Datos de contacto inválidos', parseResult.error.errors);
      }

      const data = parseResult.data;
      const tenantId = req.user!.tenantId;
      const userId = req.user!.userId;

      // Transform to camelCase DTO
      const dto: UpdatePartnerDto = {};
      if (data.name !== undefined) dto.name = data.name;
      if (data.legalName !== undefined || data.legal_name !== undefined) {
        dto.legalName = data.legalName ?? data.legal_name;
      }
      if (data.isCustomer !== undefined || data.is_customer !== undefined) {
        dto.isCustomer = data.isCustomer ?? data.is_customer;
      }
      if (data.isSupplier !== undefined || data.is_supplier !== undefined) {
        dto.isSupplier = data.isSupplier ?? data.is_supplier;
      }
      if (data.isEmployee !== undefined || data.is_employee !== undefined) {
        dto.isEmployee = data.isEmployee ?? data.is_employee;
      }
      if (data.email !== undefined) dto.email = data.email;
      if (data.phone !== undefined) dto.phone = data.phone;
      if (data.mobile !== undefined) dto.mobile = data.mobile;
      if (data.website !== undefined) dto.website = data.website;
      if (data.taxId !== undefined || data.tax_id !== undefined) {
        dto.taxId = data.taxId ?? data.tax_id;
      }
      if (data.companyId !== undefined || data.company_id !== undefined) {
        dto.companyId = data.companyId ?? data.company_id;
      }
      if (data.parentId !== undefined || data.parent_id !== undefined) {
        dto.parentId = data.parentId ?? data.parent_id;
      }
      if (data.currencyId !== undefined || data.currency_id !== undefined) {
        dto.currencyId = data.currencyId ?? data.currency_id;
      }
      if (data.notes !== undefined) dto.notes = data.notes;
      if (data.active !== undefined) dto.active = data.active;

      const partner = await partnersService.update(id, dto, tenantId, userId);

      const response: ApiResponse = {
        success: true,
        data: partner,
        message: 'Contacto actualizado exitosamente',
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }

  async delete(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const { id } = req.params;
      const tenantId = req.user!.tenantId;
      const userId = req.user!.userId;

      await partnersService.delete(id, tenantId, userId);

      const response: ApiResponse = {
        success: true,
        message: 'Contacto eliminado exitosamente',
      };

      res.json(response);
    } catch (error) {
      next(error);
    }
  }
}

export const partnersController = new PartnersController();
