import { Controller, Delete, Get, Middleware, Post, Put } from '@overnightjs/core';
import { Request, Response } from 'express';
import { auth, AuthRequest } from '../middleware/auth';
import Doctor from '../models/Doctor';
import Patient from '../models/Patient';
import User from '../models/User';
import AppointmentService from '../services/AppointmentService';

@Controller('api/appointments')
export class AppointmentController {
  @Get()
  @Middleware(auth)
  async getAllAppointments(req: Request, res: Response): Promise<void> {
    try {
      const userId = (req as AuthRequest).user.userId;
      const role = (req as AuthRequest).user.role;
      const upcoming = req.query.upcoming === 'true';
      const limit = parseInt(req.query.limit as string) || 20;
      const page = parseInt(req.query.page as string) || 1;
      const status = (req.query.status as string) || undefined;

      let doctorId: string | undefined;
      let doctorIds: string[] | undefined;
      let patientId: string | undefined;

      if (role === 'doctor' || role === 'dentist') {
        const user = await User.findById(userId).select('ownerId');
        const isPrimaryDoctor = !user?.ownerId;

        if (isPrimaryDoctor) {
          // Primary doctor: fetch their own + all team members' doctor IDs
          const teamUsers = await User.find({
            $or: [{ _id: userId }, { ownerId: userId }]
          }).select('_id');
          const teamUserIds = teamUsers.map(u => u._id);
          const teamDoctors = await Doctor.find({ userId: { $in: teamUserIds } }).select('_id');
          doctorIds = teamDoctors.map(d => d._id.toString());
        } else {
          // Team member: only see own appointments
          const doctor = await Doctor.findOne({ userId });
          doctorId = doctor?._id.toString();
        }
      }

      if (role === 'patient') {
        const patient = await Patient.findOne({ userId });
        patientId = patient?._id.toString();
      }

      if (upcoming) {
        const appointments = await AppointmentService.getDashboardAppointments(limit, upcoming, doctorId, patientId, doctorIds);
        res.json({ success: true, data: appointments });
        return;
      }

      const result = await AppointmentService.getAppointmentsPaginated({
        page,
        limit,
        doctorId,
        doctorIds,
        patientId,
        status,
      });

      res.json({
        success: true,
        data: result.data,
        meta: {
          total: result.total,
          page: result.page,
          limit: result.limit,
          totalPages: Math.max(1, Math.ceil(result.total / result.limit)),
        },
      });
    } catch (error: any) {
      res.status(500).json({ success: false, error: error.message });
    }
  }

  @Get(':id')
  async getAppointmentById(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params;
      const appointment = await AppointmentService.getAppointmentById(id);
      if (!appointment) {
        res.status(404).json({ success: false, error: 'Appointment not found' });
        return;
      }
      res.json({ success: true, data: appointment });
    } catch (error: any) {
      res.status(500).json({ success: false, error: error.message });
    }
  }

  @Post()
  async createAppointment(req: Request, res: Response): Promise<void> {
    try {
      const appointment = await AppointmentService.createAppointment(req.body);
      res.status(201).json({ success: true, data: appointment });
    } catch (error: any) {
      res.status(400).json({ success: false, error: error.message });
    }
  }
  @Put(':id')
  async updateAppointment(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params;
      const appointment = await AppointmentService.updateAppointment(id, req.body);
      if (!appointment) {
        res.status(404).json({ success: false, error: 'Appointment not found' });
        return;
      }
      res.json({ success: true, data: appointment });
    } catch (error: any) {
      res.status(400).json({ success: false, error: error.message });
    }
  }

  @Put(':id/cancel')
  async cancelAppointment(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params;
      const appointment = await AppointmentService.cancelAppointment(id);
      if (!appointment) {
        res.status(404).json({ success: false, error: 'Appointment not found' });
        return;
      }
      res.json({ success: true, data: appointment, message: 'Appointment cancelled successfully' });
    } catch (error: any) {
      res.status(500).json({ success: false, error: error.message });
    }
  }
  @Delete(':id')

  async deleteAppointment(req: Request, res: Response): Promise<void> {
    try {
      const { id } = req.params;
      const appointment = await AppointmentService.deleteAppointment(id);
      if (!appointment) {
        res.status(404).json({ success: false, error: 'Appointment not found' });
        return;
      }
      res.json({ success: true, message: 'Appointment deleted successfully' });
    } catch (error: any) {
      res.status(500).json({ success: false, error: error.message });
    }
  }
  @Get('patient/:patientId')

  async getAppointmentsByPatient(req: Request, res: Response): Promise<void> {
    try {
      const { patientId } = req.params;
      const appointments = await AppointmentService.getAppointmentsByPatient(patientId);
      res.json({ success: true, data: appointments });
    } catch (error: any) {
      res.status(500).json({ success: false, error: error.message });
    }
  }
  @Get('doctor/:doctorId')
  async getAppointmentsByDoctor(req: Request, res: Response): Promise<void> {
    try {
      const { doctorId } = req.params;
      const appointments = await AppointmentService.getAppointmentsByDoctor(doctorId);
      res.json({ success: true, data: appointments });
    } catch (error: any) {
      res.status(500).json({ success: false, error: error.message });
    }
  }
}
export default new AppointmentController();
