import {
  Injectable, NotFoundException, ConflictException
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, Between } from 'typeorm';
import { PublicHoliday, HolidayScope } from './entities/public-holiday.entity';
import { CreateHolidayDto } from './dto/create-holiday.dto';
import { UpdateHolidayDto } from './dto/update-holiday.dto';
import { User } from '../users/entities/user.entity';

@Injectable()
export class HolidaysService {
  constructor(
    @InjectRepository(PublicHoliday)
    private holidayRepo: Repository<PublicHoliday>,
  ) {}

  // ─── Lister tous les jours fériés (avec filtre année optionnel) ──────────────
  async findAll(year?: number): Promise<PublicHoliday[]> {
    if (year) {
      return this.holidayRepo.find({
        where: {
          date: Between(
            new Date(`${year}-01-01`),
            new Date(`${year}-12-31`),
          ),
        },
        order: { date: 'ASC' },
      });
    }

    return this.holidayRepo.find({ order: { date: 'ASC' } });
  }

  // ─── Trouver un jour férié par ID ────────────────────────────────────────────
  async findOne(id: number): Promise<PublicHoliday> {
    const holiday = await this.holidayRepo.findOne({ where: { id } });
    if (!holiday) throw new NotFoundException('Jour férié introuvable');
    return holiday;
  }

  // ─── Créer un jour férié ─────────────────────────────────────────────────────
  async create(dto: CreateHolidayDto, author: User): Promise<PublicHoliday> {
    const date = new Date(dto.date);

    // Vérifier doublon
    const exists = await this.holidayRepo.findOne({ where: { date } });
    if (exists) {
      throw new ConflictException(
        `Un jour férié existe déjà pour la date ${dto.date} : ${exists.label}`
      );
    }

    const holiday = this.holidayRepo.create({
      date,
      label: dto.label,
      is_exceptional: dto.is_exceptional ?? false,
      applies_to: dto.applies_to ?? HolidayScope.ALL,
      created_by: author,
    });

    return this.holidayRepo.save(holiday);
  }

  // ─── Mettre à jour un jour férié ─────────────────────────────────────────────
  async update(id: number, dto: UpdateHolidayDto): Promise<PublicHoliday> {
    const holiday = await this.findOne(id);

    if (dto.date) {
      const date = new Date(dto.date);
      // Vérifier doublon sur une autre entrée
      const exists = await this.holidayRepo.findOne({ where: { date } });
      if (exists && exists.id !== id) {
        throw new ConflictException(
          `Un jour férié existe déjà pour cette date : ${exists.label}`
        );
      }
      holiday.date = date;
    }

    if (dto.label)        holiday.label        = dto.label;
    if (dto.is_exceptional !== undefined) holiday.is_exceptional = dto.is_exceptional;
    if (dto.applies_to)   holiday.applies_to   = dto.applies_to;

    return this.holidayRepo.save(holiday);
  }

  // ─── Supprimer un jour férié ─────────────────────────────────────────────────
  async remove(id: number): Promise<{ message: string }> {
    const holiday = await this.findOne(id);
    await this.holidayRepo.remove(holiday);
    return { message: `Jour férié "${holiday.label}" supprimé` };
  }

  // ─── Jours fériés d'une période (utilisé par le calcul congés) ──────────────
  async findByPeriod(startDate: Date, endDate: Date): Promise<PublicHoliday[]> {
    return this.holidayRepo.find({
      where: { date: Between(startDate, endDate) },
      order: { date: 'ASC' },
    });
  }

  // ─── Jours fériés de l'année en cours (utilisé par le planning) ─────────────
  async findCurrentYear(): Promise<PublicHoliday[]> {
    return this.findAll(new Date().getFullYear());
  }
}