import { Holiday, HolidayType } from '@models/Holiday';
import { Op } from 'sequelize';
import logger from '@utils/logger';
import dayjs from 'dayjs';

export class HolidayService {
  /**
   * Get all holidays within a date range
   */
  async getHolidaysInRange(startDate: Date | string, endDate: Date | string): Promise<string[]> {
    try {
      const holidays = await Holiday.findAll({
        where: {
          holidayDate: {
            [Op.between]: [dayjs(startDate).format('YYYY-MM-DD'), dayjs(endDate).format('YYYY-MM-DD')]
          },
          isActive: true
        },
        attributes: ['holidayDate'],
        raw: true
      });

      return holidays.map((h: any) => h.holidayDate || h.holiday_date);
    } catch (error) {
      logger.error('[Holiday Service] Error fetching holidays:', error);
      return [];
    }
  }

  /**
   * Check if a specific date is a holiday
   */
  async isHoliday(date: Date | string): Promise<boolean> {
    try {
      const dateStr = dayjs(date).format('YYYY-MM-DD');
      const holiday = await Holiday.findOne({
        where: {
          holidayDate: dateStr,
          isActive: true
        }
      });

      return !!holiday;
    } catch (error) {
      logger.error('[Holiday Service] Error checking holiday:', error);
      return false;
    }
  }

  /**
   * Check if a date is a working day (not weekend or holiday)
   */
  async isWorkingDay(date: Date | string): Promise<boolean> {
    const day = dayjs(date);
    const dayOfWeek = day.day(); // 0 = Sunday, 6 = Saturday

    // Check if weekend
    if (dayOfWeek === 0 || dayOfWeek === 6) {
      return false;
    }

    // Check if holiday
    const isHol = await this.isHoliday(date);
    return !isHol;
  }

  /**
   * Add a new holiday
   */
  async createHoliday(holidayData: {
    holidayDate: string;
    holidayName: string;
    description?: string;
    holidayType?: HolidayType;
    isRecurring?: boolean;
    recurrenceRule?: string;
    appliesToDepartments?: string[];
    appliesToLocations?: string[];
    createdBy: string;
  }): Promise<Holiday> {
    try {
      const holiday = await Holiday.create({
        ...holidayData,
        isActive: true
      } as any);

      logger.info(`[Holiday Service] Holiday created: ${holidayData.holidayName} on ${holidayData.holidayDate}`);
      return holiday;
    } catch (error) {
      logger.error('[Holiday Service] Error creating holiday:', error);
      throw error;
    }
  }

  /**
   * Update a holiday
   */
  async updateHoliday(holidayId: string, updates: any, updatedBy: string): Promise<Holiday | null> {
    try {
      const holiday = await Holiday.findByPk(holidayId);
      if (!holiday) {
        throw new Error('Holiday not found');
      }

      await holiday.update({
        ...updates,
        updatedBy,
        updatedAt: new Date()
      });

      logger.info(`[Holiday Service] Holiday updated: ${holidayId}`);
      return holiday;
    } catch (error) {
      logger.error('[Holiday Service] Error updating holiday:', error);
      throw error;
    }
  }

  /**
   * Delete (deactivate) a holiday
   */
  async deleteHoliday(holidayId: string): Promise<boolean> {
    try {
      await Holiday.update(
        { isActive: false },
        { where: { holidayId } }
      );

      logger.info(`[Holiday Service] Holiday deactivated: ${holidayId}`);
      return true;
    } catch (error) {
      logger.error('[Holiday Service] Error deleting holiday:', error);
      throw error;
    }
  }

  /**
   * Get all active holidays
   */
  async getAllActiveHolidays(year?: number): Promise<Holiday[]> {
    try {
      const whereClause: any = { isActive: true };

      if (year) {
        const startDate = `${year}-01-01`;
        const endDate = `${year}-12-31`;
        whereClause.holidayDate = {
          [Op.between]: [startDate, endDate]
        };
      }

      const holidays = await Holiday.findAll({
        where: whereClause,
        order: [['holidayDate', 'ASC']]
      });

      return holidays;
    } catch (error) {
      logger.error('[Holiday Service] Error fetching holidays:', error);
      return [];
    }
  }

  /**
   * Get holidays by year for calendar view
   */
  async getHolidayCalendar(year: number): Promise<any[]> {
    try {
      const startDate = `${year}-01-01`;
      const endDate = `${year}-12-31`;

      const holidays = await Holiday.findAll({
        where: {
          holidayDate: {
            [Op.between]: [startDate, endDate]
          },
          isActive: true
        },
        order: [['holidayDate', 'ASC']]
      });

      return holidays.map((h: any) => ({
        date: h.holidayDate || h.holiday_date,
        name: h.holidayName || h.holiday_name,
        description: h.description,
        type: h.holidayType || h.holiday_type,
        isRecurring: h.isRecurring || h.is_recurring
      }));
    } catch (error) {
      logger.error('[Holiday Service] Error fetching holiday calendar:', error);
      return [];
    }
  }

  /**
   * Import multiple holidays (bulk upload)
   */
  async bulkImportHolidays(holidays: any[], createdBy: string): Promise<{ success: number; failed: number }> {
    let success = 0;
    let failed = 0;

    for (const holiday of holidays) {
      try {
        await this.createHoliday({
          ...holiday,
          createdBy
        });
        success++;
      } catch (error) {
        failed++;
        logger.error(`[Holiday Service] Failed to import holiday: ${holiday.holidayName}`, error);
      }
    }

    logger.info(`[Holiday Service] Bulk import complete: ${success} success, ${failed} failed`);
    return { success, failed };
  }
}

export const holidayService = new HolidayService();

