const bcrypt = require('bcrypt');
const logger = require('../utils/logger');
const BaseController = require('./base.controller');
const {
  Doctor,
  Especialista,
  Especialidad
} = require('../models');

class DoctorController extends BaseController {
  constructor() {
    super(Doctor, 'Doctor', ['Name', 'LastName', 'Email', 'MedicalSchoolNumber']);
  }

  // Sobrescribir getById para excluir password e incluir especialidades
  getById = async (req, res, next) => {
    try {
      const { id } = req.params;

      const doctor = await this.model.findByPk(id, {
        attributes: { exclude: ['Password'] },
        // include: [
        //   {
        //     model: Especialista,
        //     as: 'especialistas',
        //     include: [
        //       {
        //         model: Especialidad,
        //         as: 'especialidad',
        //         attributes: ['Id', 'Name']
        //       }
        //     ]
        //   }
        // ]
      });

      if (!doctor) {
        return res.status(404).json({
          success: false,
          message: 'Doctor no encontrado'
        });
      }

      res.json({
        success: true,
        message: 'Doctor obtenido exitosamente',
        data: doctor
      });
    } catch (error) {
      next(error);
    }
  };

  // Sobrescribir getAll para excluir password
  getAll = async (req, res, next) => {
    try {
      const { rows, count } = await this.model.findAndCountAll({
        attributes: { exclude: ['Password'] },
        // include: [
        //   {
        //     model: Especialista,
        //     as: 'especialistas',
        //     include: [
        //       {
        //         model: Especialidad,
        //         as: 'especialidad',
        //         attributes: ['Id', 'Name']
        //       }
        //     ]
        //   }
        // ],
        order: [['LastName', 'ASC'], ['Name', 'ASC']]
      });

      res.json({
        success: true,
        message: 'Listado completo de doctores',
        data: rows,
        total: count
      });
    } catch (error) {
      next(error);
    }
  };

  // GET /doctors/email/:email → BÚSQUEDA SOLO POR EMAIL (parcial)
  findByEmail = async (req, res, next) => {
    try {
      const {
        email
      } = req.params;
      const doctor = await Doctor.findOne({
        where: {
          Email: email
        },
        attributes: {
          exclude: ['Password']
        }
      });

      if (!doctor) {
        logger.warn('Doctor no encontrado', {
          email,
          ip: req.ip
        });
        return res.status(404).json({
          success: false,
          message: 'Doctor no encontrado'
        });
      }
      logger.info('Doctor encontrado', {
        email,
        ip: req.ip
      });
      res.json({
        success: true,
        data: doctor
      });
    } catch (error) {
      next(error);
    }
  };

  /**
   * Actualizar SOLO el atributo Code del doctor
   * - id del doctor → req.params.id
   * - code → req.body.code
   */
  updateDoctorCode = async (req, res) => {
    try {
      const { id } = req.params;           // ID del doctor en la URL
      const { code } = req.body;           // Código que llega en el body
      // Validar que el ID esté presente
      if (!id) {
        return res.status(400).json({
          success: false,
          message: 'El ID del doctor es requerido en la URL',
        });
      }
      // Validar que el código llegue y no esté vacío
      if (!code || typeof code !== 'string' || code.trim() === '') {
        return res.status(400).json({
          success: false,
          message: 'El campo "code" es requerido y no puede estar vacío',
        });
      }

      // Buscar al doctor por ID
      const doctor = await Doctor.findByPk(id);

      if (!doctor) {
        logger.warn('Intento de actualizar Code - Doctor no encontrado', {
          doctorId: id,
          ip: req.ip,
        });
        return res.status(404).json({
          success: false,
          message: 'Doctor no encontrado',
        });
      }

      // ACTUALIZAR SOLO EL CAMPO Code
      await doctor.update({
        Code: code.trim(),   // Guardamos exactamente el código recibido
        // Si también usas CodeExpiresAt y quieres actualizarlo, descomenta:
        // CodeExpiresAt: new Date(Date.now() + 15 * 60 * 1000), // 15 min de vida
      });

      logger.auth('Código actualizado exitosamente - Doctor', {
        doctorId: doctor.Id,
        codeLength: code.trim().length,
        ip: req.ip,
      });

      return res.json({
        success: true,
        message: 'Código actualizado correctamente',
        data: {
          doctorId: doctor.Id,
          updatedCode: code.trim(), // opcional: solo en dev si quieres verlo
        },
      });

    } catch (error) {
      logger.error('Error al actualizar el código del doctor', {
        error: error.message,
        stack: error.stack,
        doctorId: req.params.id,
      });

      return res.status(500).json({
        success: false,
        message: 'Error en el servidor',
        error: process.env.NODE_ENV === 'development' ? error.message : undefined,
      });
    }
  };

  /**
   * Resetear contraseña de Doctor usando MedicalSchoolNumber
   */
  resetPasswordByMedicalSchoolNumber = async (req, res) => {
    try {
      const {
        doctorId,
        newPassword
      } = req.body;

      // Validar campos requeridos
      if (!doctorId || !newPassword) {
        return res.status(400).json({
          success: false,
          message: 'ID de doctor y nueva contraseña son requeridos'
        });
      }

      // Validar longitud de contraseña
      if (newPassword.length < 2) {
        return res.status(400).json({
          success: false,
          message: 'La contraseña debe tener al menos 2 caracteres'
        });
      }

      // Buscar doctor por número de matrícula médica
      const doctor = await Doctor.findOne({
        where: {
          id: doctorId
        }
      });

      if (!doctor) {
        logger.warn('Reset password fallido - Doctor no encontrado', {
          medicalSchoolNumber,
          ip: req.ip
        });
        return res.status(404).json({
          success: false,
          message: 'No se encontró un doctor con ese número de matrícula médica'
        });
      }

      // Hashear nueva contraseña
      const hashedPassword = await bcrypt.hash(
        newPassword,
        parseInt(process.env.BCRYPT_ROUNDS) || 10
      );

      // Actualizar contraseña
      await doctor.update({
        Password: hashedPassword
      });

      // Log exitoso
      logger.auth('Contraseña reseteada exitosamente - Doctor', {
        doctorId: doctor.Id,
        medicalSchoolNumber: doctor.MedicalSchoolNumber,
        ip: req.ip
      });

      res.json({
        success: true,
        message: 'Contraseña reseteada exitosamente',
        data: {
          email: doctor.Email,
          name: doctor.Name,
          especialidad: doctor.Especialidad
        }
      });

    } catch (error) {
      logger.error('Error al resetear contraseña de doctor', {
        error: error.message,
        stack: error.stack
      });
      res.status(500).json({
        success: false,
        message: 'Error en el servidor',
        error: process.env.NODE_ENV === 'development' ? error.message : undefined
      });
    }
  };

  /**
   * Verificar si existe un doctor por número de matrícula médica
   */
  verifyMedicalSchoolNumberExists = async (req, res) => {
    try {
      const { medicalSchoolNumber } = req.params;

      const doctor = await Doctor.findOne({
        where: { MedicalSchoolNumber: medicalSchoolNumber },
        attributes: ['Id', 'Name', 'Email']
      });

      if (!doctor) {
        return res.status(404).json({
          success: false,
          message: 'Matrícula no encontrada'
        });
      }

      res.json({
        success: true,
        message: 'Doctor encontrado',
        data: {
          name: doctor.Name,
          email: doctor.Email.replace(/(.{2})(.*)(@.*)/, '$1***$3')
        }
      });
    } catch (error) {
      logger.error('Error verificando matrícula', error);
      res.status(500).json({ success: false, message: 'Error en servidor' });
    }
  };

  /**
   * Solicitar código de verificación para doctor
   */
  requestVerificationCode = async (req, res) => {
    try {
      const {
        medicalSchoolNumber
      } = req.body;

      const doctor = await Doctor.findOne({
        where: {
          MedicalSchoolNumber: medicalSchoolNumber
        }
      });

      if (!doctor) {
        return res.status(404).json({
          success: false,
          message: 'No se encontró un doctor con ese número de matrícula médica'
        });
      }

      // Generar código de 6 dígitos
      const verificationCode = Math.floor(100000 + Math.random() * 900000).toString();

      // TODO: Aquí deberías enviar el código por email o SMS

      logger.auth('Código de verificación generado - Doctor', {
        doctorId: doctor.Id,
        medicalSchoolNumber: doctor.MedicalSchoolNumber,
        code: verificationCode, // En producción NO logear el código
        ip: req.ip
      });

      // En desarrollo, devolver el código (NUNCA en producción)
      if (process.env.NODE_ENV === 'development') {
        return res.json({
          success: true,
          message: 'Código de verificación generado',
          code: verificationCode // Solo para desarrollo
        });
      }

      res.json({
        success: true,
        message: 'Código de verificación enviado al email registrado'
      });

    } catch (error) {
      logger.error('Error al solicitar código de verificación', {
        error: error.message
      });
      res.status(500).json({
        success: false,
        message: 'Error en el servidor'
      });
    }
  };

  /**
   * Resetear contraseña con código de verificación
   */
  resetPasswordWithCode = async (req, res) => {
    try {
      const {
        medicalSchoolNumber,
        verificationCode,
        newPassword
      } = req.body;

      // Validar campos
      if (!medicalSchoolNumber || !verificationCode || !newPassword) {
        return res.status(400).json({
          success: false,
          message: 'Todos los campos son requeridos'
        });
      }

      // TODO: Verificar el código de verificación desde cache/base de datos

      // Buscar doctor
      const doctor = await Doctor.findOne({
        where: {
          MedicalSchoolNumber: medicalSchoolNumber
        }
      });

      if (!doctor) {
        return res.status(404).json({
          success: false,
          message: 'Doctor no encontrado'
        });
      }

      // Hashear nueva contraseña
      const hashedPassword = await bcrypt.hash(
        newPassword,
        parseInt(process.env.BCRYPT_ROUNDS) || 10
      );

      // Actualizar contraseña
      await doctor.update({
        Password: hashedPassword
      });

      logger.auth('Contraseña reseteada con código - Doctor', {
        doctorId: doctor.Id,
        ip: req.ip
      });

      res.json({
        success: true,
        message: 'Contraseña reseteada exitosamente'
      });

    } catch (error) {
      logger.error('Error al resetear contraseña con código', {
        error: error.message
      });
      res.status(500).json({
        success: false,
        message: 'Error en el servidor'
      });
    }
  };
}

module.exports = new DoctorController();