import { Response, NextFunction } from 'express';
import { z } from 'zod';
import { tenantsService } from './tenants.service.js';
import { TenantStatus } from '../auth/entities/index.js';
import { ApiResponse, AuthenticatedRequest, ValidationError, PaginationParams } from '../../shared/types/index.js';

// Validation schemas
const createTenantSchema = z.object({
  name: z.string().min(2, 'El nombre debe tener al menos 2 caracteres'),
  subdomain: z.string()
    .min(3, 'El subdominio debe tener al menos 3 caracteres')
    .max(50, 'El subdominio no puede exceder 50 caracteres')
    .regex(/^[a-z0-9-]+$/, 'El subdominio solo puede contener letras minúsculas, números y guiones'),
  plan: z.enum(['basic', 'standard', 'premium', 'enterprise']).optional(),
  maxUsers: z.number().int().min(1).max(1000).optional(),
  settings: z.record(z.any()).optional(),
});

const updateTenantSchema = z.object({
  name: z.string().min(2).optional(),
  plan: z.enum(['basic', 'standard', 'premium', 'enterprise']).optional(),
  maxUsers: z.number().int().min(1).max(1000).optional(),
  settings: z.record(z.any()).optional(),
});

const updateSettingsSchema = z.object({
  settings: z.record(z.any()),
});

export class TenantsController {
  /**
   * GET /tenants - List all tenants (super_admin only)
   */
  async findAll(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      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 || 'name';
      const sortOrder = (req.query.sortOrder as 'asc' | 'desc') || 'asc';

      const params: PaginationParams = { page, limit, sortBy, sortOrder };

      // Build filter
      const filter: { status?: TenantStatus; search?: string } = {};
      if (req.query.status) {
        filter.status = req.query.status as TenantStatus;
      }
      if (req.query.search) {
        filter.search = req.query.search as string;
      }

      const result = await tenantsService.findAll(params, filter);

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

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

  /**
   * GET /tenants/current - Get current user's tenant
   */
  async getCurrent(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.user!.tenantId;
      const tenant = await tenantsService.findById(tenantId);

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

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

  /**
   * GET /tenants/:id - Get tenant by ID (super_admin only)
   */
  async findById(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.params.id;
      const tenant = await tenantsService.findById(tenantId);

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

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

  /**
   * GET /tenants/:id/stats - Get tenant statistics
   */
  async getStats(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.params.id;
      const stats = await tenantsService.getTenantStats(tenantId);

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

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

  /**
   * POST /tenants - Create new tenant (super_admin only)
   */
  async create(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const validation = createTenantSchema.safeParse(req.body);
      if (!validation.success) {
        throw new ValidationError('Datos inválidos', validation.error.errors);
      }

      const createdBy = req.user!.userId;
      const tenant = await tenantsService.create(validation.data, createdBy);

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

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

  /**
   * PUT /tenants/:id - Update tenant
   */
  async update(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const validation = updateTenantSchema.safeParse(req.body);
      if (!validation.success) {
        throw new ValidationError('Datos inválidos', validation.error.errors);
      }

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

      const tenant = await tenantsService.update(tenantId, validation.data, updatedBy);

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

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

  /**
   * POST /tenants/:id/suspend - Suspend tenant (super_admin only)
   */
  async suspend(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.params.id;
      const updatedBy = req.user!.userId;

      const tenant = await tenantsService.suspend(tenantId, updatedBy);

      const response: ApiResponse = {
        success: true,
        data: tenant,
        message: 'Tenant suspendido exitosamente',
      };

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

  /**
   * POST /tenants/:id/activate - Activate tenant (super_admin only)
   */
  async activate(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.params.id;
      const updatedBy = req.user!.userId;

      const tenant = await tenantsService.activate(tenantId, updatedBy);

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

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

  /**
   * DELETE /tenants/:id - Soft delete tenant (super_admin only)
   */
  async delete(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.params.id;
      const deletedBy = req.user!.userId;

      await tenantsService.delete(tenantId, deletedBy);

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

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

  /**
   * GET /tenants/:id/settings - Get tenant settings
   */
  async getSettings(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.params.id;
      const settings = await tenantsService.getSettings(tenantId);

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

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

  /**
   * PUT /tenants/:id/settings - Update tenant settings
   */
  async updateSettings(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const validation = updateSettingsSchema.safeParse(req.body);
      if (!validation.success) {
        throw new ValidationError('Datos inválidos', validation.error.errors);
      }

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

      const settings = await tenantsService.updateSettings(
        tenantId,
        validation.data.settings,
        updatedBy
      );

      const response: ApiResponse = {
        success: true,
        data: settings,
        message: 'Configuración actualizada exitosamente',
      };

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

  /**
   * GET /tenants/:id/can-add-user - Check if tenant can add more users
   */
  async canAddUser(req: AuthenticatedRequest, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.params.id;
      const result = await tenantsService.canAddUser(tenantId);

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

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

export const tenantsController = new TenantsController();
