/**
 * BranchSchedule Service
 * Servicio para gestión de horarios de sucursales
 *
 * @module Branches
 */

import { Repository, FindOptionsWhere } from 'typeorm';
import { AppDataSource } from '../../../shared/database/typeorm.config';
import { BranchSchedule, ScheduleType } from '../entities/branch-schedule.entity';
import { ServiceContext } from './branch.service';

export interface CreateBranchScheduleDto {
  branchId: string;
  name: string;
  description?: string;
  scheduleType?: ScheduleType;
  dayOfWeek?: number;
  specificDate?: Date;
  openTime: string;
  closeTime: string;
  shifts?: Array<{ name: string; start: string; end: string }>;
  isActive?: boolean;
}

export interface UpdateBranchScheduleDto {
  name?: string;
  description?: string;
  scheduleType?: ScheduleType;
  dayOfWeek?: number;
  specificDate?: Date;
  openTime?: string;
  closeTime?: string;
  shifts?: Array<{ name: string; start: string; end: string }>;
  isActive?: boolean;
}

export interface BranchScheduleFilters {
  branchId?: string;
  scheduleType?: ScheduleType;
  dayOfWeek?: number;
  isActive?: boolean;
}

export class BranchScheduleService {
  private repository: Repository<BranchSchedule>;

  constructor() {
    this.repository = AppDataSource.getRepository(BranchSchedule);
  }

  async findAll(_ctx: ServiceContext, filters?: BranchScheduleFilters): Promise<BranchSchedule[]> {
    const where: FindOptionsWhere<BranchSchedule> = {};

    if (filters?.branchId) {
      where.branchId = filters.branchId;
    }

    if (filters?.scheduleType) {
      where.scheduleType = filters.scheduleType;
    }

    if (filters?.dayOfWeek !== undefined) {
      where.dayOfWeek = filters.dayOfWeek;
    }

    if (filters?.isActive !== undefined) {
      where.isActive = filters.isActive;
    }

    return this.repository.find({
      where,
      relations: ['branch'],
      order: { dayOfWeek: 'ASC', openTime: 'ASC' },
    });
  }

  async findById(_ctx: ServiceContext, id: string): Promise<BranchSchedule | null> {
    return this.repository.findOne({
      where: { id },
      relations: ['branch'],
    });
  }

  async findByBranch(_ctx: ServiceContext, branchId: string): Promise<BranchSchedule[]> {
    return this.repository.find({
      where: { branchId, isActive: true },
      order: { dayOfWeek: 'ASC', openTime: 'ASC' },
    });
  }

  async findRegularSchedule(_ctx: ServiceContext, branchId: string): Promise<BranchSchedule[]> {
    return this.repository.find({
      where: { branchId, scheduleType: 'regular', isActive: true },
      order: { dayOfWeek: 'ASC' },
    });
  }

  async findHolidaySchedule(_ctx: ServiceContext, branchId: string): Promise<BranchSchedule[]> {
    return this.repository.find({
      where: { branchId, scheduleType: 'holiday', isActive: true },
      order: { specificDate: 'ASC' },
    });
  }

  async findScheduleForDate(
    _ctx: ServiceContext,
    branchId: string,
    date: Date
  ): Promise<BranchSchedule | null> {
    // First check for specific date (holiday or special)
    const specificSchedule = await this.repository.findOne({
      where: {
        branchId,
        specificDate: date,
        isActive: true,
      },
    });

    if (specificSchedule) {
      return specificSchedule;
    }

    // Fall back to regular schedule for day of week
    const dayOfWeek = date.getDay();
    return this.repository.findOne({
      where: {
        branchId,
        scheduleType: 'regular',
        dayOfWeek,
        isActive: true,
      },
    });
  }

  async create(_ctx: ServiceContext, data: CreateBranchScheduleDto): Promise<BranchSchedule> {
    const schedule = this.repository.create(data);
    return this.repository.save(schedule);
  }

  async update(
    ctx: ServiceContext,
    id: string,
    data: UpdateBranchScheduleDto
  ): Promise<BranchSchedule | null> {
    const schedule = await this.findById(ctx, id);
    if (!schedule) {
      return null;
    }

    Object.assign(schedule, data);
    return this.repository.save(schedule);
  }

  async delete(_ctx: ServiceContext, id: string): Promise<boolean> {
    const result = await this.repository.delete({ id });
    return result.affected ? result.affected > 0 : false;
  }

  async createWeeklySchedule(
    _ctx: ServiceContext,
    branchId: string,
    weeklyHours: Array<{
      dayOfWeek: number;
      openTime: string;
      closeTime: string;
      shifts?: Array<{ name: string; start: string; end: string }>;
    }>
  ): Promise<BranchSchedule[]> {
    // Delete existing regular schedules for this branch
    await this.repository.delete({
      branchId,
      scheduleType: 'regular',
    });

    // Create new schedules
    const schedules = weeklyHours.map(hours =>
      this.repository.create({
        branchId,
        name: `Regular - Day ${hours.dayOfWeek}`,
        scheduleType: 'regular',
        dayOfWeek: hours.dayOfWeek,
        openTime: hours.openTime,
        closeTime: hours.closeTime,
        shifts: hours.shifts || [],
        isActive: true,
      })
    );

    return this.repository.save(schedules);
  }

  async isBranchOpenAt(
    ctx: ServiceContext,
    branchId: string,
    dateTime: Date
  ): Promise<boolean> {
    const schedule = await this.findScheduleForDate(ctx, branchId, dateTime);
    if (!schedule) {
      return false;
    }

    const timeStr = dateTime.toTimeString().slice(0, 5); // HH:MM format
    return timeStr >= schedule.openTime && timeStr <= schedule.closeTime;
  }
}
