import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { usersService } from './users.service.js';
import { ApiResponse, AuthenticatedRequest, ValidationError, PaginationParams } from '../../shared/types/index.js';

const createUserSchema = z.object({
  email: z.string().email('Email inválido'),
  password: z.string().min(8, 'La contraseña debe tener al menos 8 caracteres'),
  // Soporta ambos formatos: full_name (legacy) o firstName+lastName (frontend)
  full_name: z.string().min(2, 'El nombre debe tener al menos 2 caracteres').optional(),
  firstName: z.string().min(2, 'Nombre debe tener al menos 2 caracteres').optional(),
  lastName: z.string().min(2, 'Apellido debe tener al menos 2 caracteres').optional(),
  status: z.enum(['active', 'inactive', 'pending']).optional(),
  is_superuser: z.boolean().optional(),
}).refine(
  (data) => data.full_name || (data.firstName && data.lastName),
  { message: 'Se requiere full_name o firstName y lastName', path: ['full_name'] }
);

const updateUserSchema = z.object({
  email: z.string().email('Email inválido').optional(),
  full_name: z.string().min(2).optional(),
  firstName: z.string().min(2).optional(),
  lastName: z.string().min(2).optional(),
  status: z.enum(['active', 'inactive', 'pending', 'suspended']).optional(),
});

const assignRoleSchema = z.object({
  role_id: z.string().uuid('Role ID inválido'),
});

export class UsersController {
  async getMe(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.user!.tenantId;
      const userId = req.user!.userId;

      const user = await usersService.findById(tenantId, userId);

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

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

  async findAll(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.user!.tenantId;
      const page = parseInt(req.query.page as string) || 1;
      const limit = Math.min(parseInt(req.query.limit as string) || 20, 100);
      const sortBy = req.query.sortBy as string;
      const sortOrder = req.query.sortOrder as 'asc' | 'desc';

      const params: PaginationParams = { page, limit, sortBy, sortOrder };
      const result = await usersService.findAll(tenantId, params);

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

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

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

      const user = await usersService.findById(tenantId, userId);

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

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

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

      const tenantId = req.user!.tenantId;
      const user = await usersService.create({
        ...validation.data,
        tenant_id: tenantId,
      });

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

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

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

      const tenantId = req.user!.tenantId;
      const userId = req.params.id;

      const user = await usersService.update(tenantId, userId, validation.data);

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

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

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

      await usersService.delete(tenantId, userId);

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

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

  async getRoles(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const userId = req.params.id;
      const roles = await usersService.getUserRoles(userId);

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

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

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

      const userId = req.params.id;
      await usersService.assignRole(userId, validation.data.role_id);

      const response: ApiResponse = {
        success: true,
        message: 'Rol asignado exitosamente',
      };

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

  async removeRole(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const userId = req.params.id;
      const roleId = req.params.roleId;

      await usersService.removeRole(userId, roleId);

      const response: ApiResponse = {
        success: true,
        message: 'Rol removido exitosamente',
      };

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

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

      const user = await usersService.activate(tenantId, userId, currentUserId);

      const response: ApiResponse = {
        success: true,
        data: user,
        message: 'Usuario activado exitosamente',
      };

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

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

      const user = await usersService.deactivate(tenantId, userId, currentUserId);

      const response: ApiResponse = {
        success: true,
        data: user,
        message: 'Usuario desactivado exitosamente',
      };

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

export const usersController = new UsersController();
