import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Body,
  Param,
  Query,
  UseGuards,
  NotFoundException,
} from '@nestjs/common';
import { DriversService } from './drivers.service';
import { ScheduleExportService } from './schedule-export.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles } from '../auth/decorators/roles.decorator';
import { CurrentUser } from '../auth/decorators/current-user.decorator';
import { Role } from '@prisma/client';
import { CreateDriverDto, UpdateDriverDto } from './dto';

@Controller('drivers')
@UseGuards(JwtAuthGuard, RolesGuard)
export class DriversController {
  constructor(
    private readonly driversService: DriversService,
    private readonly scheduleExportService: ScheduleExportService,
  ) {}

  @Post()
  @Roles(Role.ADMINISTRATOR, Role.COORDINATOR)
  create(@Body() createDriverDto: CreateDriverDto) {
    return this.driversService.create(createDriverDto);
  }

  @Get()
  @Roles(Role.ADMINISTRATOR, Role.COORDINATOR, Role.DRIVER)
  findAll() {
    return this.driversService.findAll();
  }

  @Get('me')
  @Roles(Role.DRIVER, Role.ADMINISTRATOR, Role.COORDINATOR)
  async getMyDriverProfile(@CurrentUser() user: any) {
    const driver = await this.driversService.findByUserId(user.id);
    if (!driver) {
      throw new NotFoundException('Driver profile not found for current user');
    }
    return driver;
  }

  /**
   * Get ICS calendar file for driver's own schedule
   * By default, returns full upcoming schedule. Pass fullSchedule=false for single day.
   */
  @Get('me/schedule/ics')
  @Roles(Role.DRIVER, Role.ADMINISTRATOR, Role.COORDINATOR)
  async getMyScheduleICS(
    @CurrentUser() user: any,
    @Query('date') dateStr?: string,
    @Query('fullSchedule') fullScheduleStr?: string,
  ) {
    const driver = await this.driversService.findByUserId(user.id);
    if (!driver) {
      throw new NotFoundException('Driver profile not found for current user');
    }
    const date = dateStr ? new Date(dateStr) : new Date();
    // Default to full schedule (true) unless explicitly set to false
    const fullSchedule = fullScheduleStr !== 'false';
    const icsContent = await this.scheduleExportService.generateICS(driver.id, date, fullSchedule);
    const filename = fullSchedule
      ? `full-schedule-${new Date().toISOString().split('T')[0]}.ics`
      : `schedule-${date.toISOString().split('T')[0]}.ics`;
    return { ics: icsContent, filename };
  }

  /**
   * Get PDF schedule for driver's own schedule
   * By default, returns full upcoming schedule. Pass fullSchedule=false for single day.
   */
  @Get('me/schedule/pdf')
  @Roles(Role.DRIVER, Role.ADMINISTRATOR, Role.COORDINATOR)
  async getMySchedulePDF(
    @CurrentUser() user: any,
    @Query('date') dateStr?: string,
    @Query('fullSchedule') fullScheduleStr?: string,
  ) {
    const driver = await this.driversService.findByUserId(user.id);
    if (!driver) {
      throw new NotFoundException('Driver profile not found for current user');
    }
    const date = dateStr ? new Date(dateStr) : new Date();
    // Default to full schedule (true) unless explicitly set to false
    const fullSchedule = fullScheduleStr !== 'false';
    const pdfBuffer = await this.scheduleExportService.generatePDF(driver.id, date, fullSchedule);
    const filename = fullSchedule
      ? `full-schedule-${new Date().toISOString().split('T')[0]}.pdf`
      : `schedule-${date.toISOString().split('T')[0]}.pdf`;
    return { pdf: pdfBuffer.toString('base64'), filename };
  }

  /**
   * Send schedule to driver's own phone via Signal
   * By default, sends full upcoming schedule. Pass fullSchedule=false for single day.
   */
  @Post('me/send-schedule')
  @Roles(Role.DRIVER, Role.ADMINISTRATOR, Role.COORDINATOR)
  async sendMySchedule(
    @CurrentUser() user: any,
    @Body() body: { date?: string; format?: 'ics' | 'pdf' | 'both'; fullSchedule?: boolean },
  ) {
    const driver = await this.driversService.findByUserId(user.id);
    if (!driver) {
      throw new NotFoundException('Driver profile not found for current user');
    }
    const date = body.date ? new Date(body.date) : new Date();
    const format = body.format || 'both';
    // Default to full schedule (true) unless explicitly set to false
    const fullSchedule = body.fullSchedule !== false;
    return this.scheduleExportService.sendScheduleToDriver(driver.id, date, format, fullSchedule);
  }

  @Patch('me')
  @Roles(Role.DRIVER)
  async updateMyProfile(@CurrentUser() user: any, @Body() updateDriverDto: UpdateDriverDto) {
    const driver = await this.driversService.findByUserId(user.id);
    if (!driver) {
      throw new NotFoundException('Driver profile not found for current user');
    }
    return this.driversService.update(driver.id, updateDriverDto);
  }

  /**
   * Send schedule to all drivers with events on a given date
   * NOTE: This static route MUST come before :id routes to avoid matching issues
   */
  @Post('send-all-schedules')
  @Roles(Role.ADMINISTRATOR, Role.COORDINATOR)
  async sendAllSchedules(
    @Body() body: { date?: string; format?: 'ics' | 'pdf' | 'both' },
  ) {
    const date = body.date ? new Date(body.date) : new Date();
    const format = body.format || 'both';

    // Get all drivers with events on this date
    const drivers = await this.driversService.findAll();
    const results: Array<{ driverId: string; driverName: string; success: boolean; message: string }> = [];

    for (const driver of drivers) {
      try {
        const result = await this.scheduleExportService.sendScheduleToDriver(
          driver.id,
          date,
          format,
        );
        results.push({
          driverId: driver.id,
          driverName: driver.name,
          success: result.success,
          message: result.message,
        });
      } catch (error: any) {
        // Skip drivers without events or phone numbers
        if (!error.message?.includes('No events')) {
          results.push({
            driverId: driver.id,
            driverName: driver.name,
            success: false,
            message: error.message,
          });
        }
      }
    }

    const successCount = results.filter((r) => r.success).length;
    return {
      success: true,
      sent: successCount,
      total: results.length,
      results,
    };
  }

  // === Routes with :id parameter MUST come AFTER all static routes ===

  @Get(':id')
  @Roles(Role.ADMINISTRATOR, Role.COORDINATOR, Role.DRIVER)
  findOne(@Param('id') id: string) {
    return this.driversService.findOne(id);
  }

  @Get(':id/schedule')
  @Roles(Role.ADMINISTRATOR, Role.COORDINATOR, Role.DRIVER)
  getSchedule(@Param('id') id: string) {
    return this.driversService.getSchedule(id);
  }

  /**
   * Send schedule to driver via Signal (ICS and/or PDF)
   */
  @Post(':id/send-schedule')
  @Roles(Role.ADMINISTRATOR, Role.COORDINATOR)
  async sendSchedule(
    @Param('id') id: string,
    @Body() body: { date?: string; format?: 'ics' | 'pdf' | 'both' },
  ) {
    const date = body.date ? new Date(body.date) : new Date();
    const format = body.format || 'both';
    return this.scheduleExportService.sendScheduleToDriver(id, date, format);
  }

  @Patch(':id')
  @Roles(Role.ADMINISTRATOR, Role.COORDINATOR)
  update(@Param('id') id: string, @Body() updateDriverDto: UpdateDriverDto) {
    return this.driversService.update(id, updateDriverDto);
  }

  @Delete(':id')
  @Roles(Role.ADMINISTRATOR, Role.COORDINATOR)
  remove(
    @Param('id') id: string,
    @Query('hard') hard?: string,
  ) {
    const isHardDelete = hard === 'true';
    return this.driversService.remove(id, isHardDelete);
  }
}
