<?php

namespace App\Enums;

use Carbon\Carbon;

class InspectionCycle
{
    const DAILY = 'daily';

    const WEEKLY = 'weekly';

    const MONTHLY = 'monthly';

    const BIMONTHLY = 'bimonthly';

    const QUARTERLY = 'quarterly';

    const SEMIANNUAL = 'semiannual';

    /**
     * 전체 주기 목록 (코드 → 라벨)
     */
    public static function all(): array
    {
        return [
            self::DAILY => '일일',
            self::WEEKLY => '주간',
            self::MONTHLY => '월간',
            self::BIMONTHLY => '2개월',
            self::QUARTERLY => '분기',
            self::SEMIANNUAL => '반년',
        ];
    }

    /**
     * 주기별 라벨 반환
     */
    public static function label(string $cycle): string
    {
        return self::all()[$cycle] ?? $cycle;
    }

    /**
     * 주기별 기간 필터 타입 반환
     */
    public static function periodType(string $cycle): string
    {
        return $cycle === self::DAILY ? 'month' : 'year';
    }

    /**
     * 주기별 그리드 열 라벨 반환
     *
     * @return array<int, string> [colIndex => label]
     */
    public static function columnLabels(string $cycle, ?string $period = null): array
    {
        return match ($cycle) {
            self::DAILY => self::dailyLabels($period),
            self::WEEKLY => self::weeklyLabels(),
            self::MONTHLY => self::monthlyLabels(),
            self::BIMONTHLY => self::bimonthlyLabels(),
            self::QUARTERLY => self::quarterlyLabels(),
            self::SEMIANNUAL => self::semiannualLabels(),
            default => self::dailyLabels($period),
        };
    }

    /**
     * 열 인덱스 → check_date 변환
     */
    public static function resolveCheckDate(string $cycle, string $period, int $colIndex): string
    {
        return match ($cycle) {
            self::DAILY => self::dailyCheckDate($period, $colIndex),
            self::WEEKLY => self::weeklyCheckDate($period, $colIndex),
            self::MONTHLY => self::monthlyCheckDate($period, $colIndex),
            self::BIMONTHLY => self::bimonthlyCheckDate($period, $colIndex),
            self::QUARTERLY => self::quarterlyCheckDate($period, $colIndex),
            self::SEMIANNUAL => self::semiannualCheckDate($period, $colIndex),
            default => self::dailyCheckDate($period, $colIndex),
        };
    }

    /**
     * check_date → year_month(period) 역산
     */
    public static function resolvePeriod(string $cycle, string $checkDate): string
    {
        $date = Carbon::parse($checkDate);

        return match ($cycle) {
            self::DAILY => $date->format('Y-m'),
            self::WEEKLY => (string) $date->isoWeekYear,
            default => $date->format('Y'),
        };
    }

    /**
     * 주기별 그리드 열 수
     */
    public static function columnCount(string $cycle, ?string $period = null): int
    {
        return count(self::columnLabels($cycle, $period));
    }

    /**
     * 주말 여부 (daily 전용)
     */
    public static function isWeekend(string $period, int $colIndex): bool
    {
        $date = Carbon::createFromFormat('Y-m', $period)->startOfMonth()->addDays($colIndex - 1);

        return in_array($date->dayOfWeek, [0, 6]);
    }

    /**
     * 해당 기간의 휴일 날짜 목록 반환 (date string Set)
     */
    public static function getHolidayDates(string $cycle, string $period): array
    {
        $tenantId = session('selected_tenant_id', 1);

        if ($cycle === self::DAILY) {
            $start = Carbon::createFromFormat('Y-m', $period)->startOfMonth();
            $end = $start->copy()->endOfMonth();
        } else {
            $start = Carbon::create((int) $period, 1, 1);
            $end = Carbon::create((int) $period, 12, 31);
        }

        $holidays = \App\Models\System\Holiday::where('tenant_id', $tenantId)
            ->where('start_date', '<=', $end->toDateString())
            ->where('end_date', '>=', $start->toDateString())
            ->get();

        $dates = [];
        foreach ($holidays as $holiday) {
            $hStart = $holiday->start_date->copy()->max($start);
            $hEnd = $holiday->end_date->copy()->min($end);
            $current = $hStart->copy();
            while ($current->lte($hEnd)) {
                $dates[$current->format('Y-m-d')] = true;
                $current->addDay();
            }
        }

        return $dates;
    }

    /**
     * 비근무일 여부 (주말 또는 휴일)
     */
    public static function isNonWorkingDay(string $checkDate, array $holidayDates = []): bool
    {
        $date = Carbon::parse($checkDate);

        return $date->isWeekend() || isset($holidayDates[$checkDate]);
    }

    // --- Daily ---
    private static function dailyLabels(?string $period): array
    {
        $date = Carbon::createFromFormat('Y-m', $period ?? now()->format('Y-m'));
        $days = $date->daysInMonth;
        $labels = [];
        for ($d = 1; $d <= $days; $d++) {
            $labels[$d] = (string) $d;
        }

        return $labels;
    }

    private static function dailyCheckDate(string $period, int $colIndex): string
    {
        return Carbon::createFromFormat('Y-m', $period)->startOfMonth()->addDays($colIndex - 1)->format('Y-m-d');
    }

    // --- Weekly ---
    private static function weeklyLabels(): array
    {
        $labels = [];
        for ($w = 1; $w <= 52; $w++) {
            $labels[$w] = $w.'주';
        }

        return $labels;
    }

    private static function weeklyCheckDate(string $year, int $colIndex): string
    {
        // ISO 주차의 월요일
        return Carbon::create((int) $year)->setISODate((int) $year, $colIndex, 1)->format('Y-m-d');
    }

    // --- Monthly ---
    private static function monthlyLabels(): array
    {
        $labels = [];
        for ($m = 1; $m <= 12; $m++) {
            $labels[$m] = $m.'월';
        }

        return $labels;
    }

    private static function monthlyCheckDate(string $year, int $colIndex): string
    {
        return Carbon::create((int) $year, $colIndex, 1)->format('Y-m-d');
    }

    // --- Bimonthly ---
    private static function bimonthlyLabels(): array
    {
        return [
            1 => '1~2월',
            2 => '3~4월',
            3 => '5~6월',
            4 => '7~8월',
            5 => '9~10월',
            6 => '11~12월',
        ];
    }

    private static function bimonthlyCheckDate(string $year, int $colIndex): string
    {
        $month = ($colIndex - 1) * 2 + 1;

        return Carbon::create((int) $year, $month, 1)->format('Y-m-d');
    }

    // --- Quarterly ---
    private static function quarterlyLabels(): array
    {
        return [
            1 => '1분기',
            2 => '2분기',
            3 => '3분기',
            4 => '4분기',
        ];
    }

    private static function quarterlyCheckDate(string $year, int $colIndex): string
    {
        $month = ($colIndex - 1) * 3 + 1;

        return Carbon::create((int) $year, $month, 1)->format('Y-m-d');
    }

    // --- Semiannual ---
    private static function semiannualLabels(): array
    {
        return [
            1 => '상반기',
            2 => '하반기',
        ];
    }

    private static function semiannualCheckDate(string $year, int $colIndex): string
    {
        $month = $colIndex === 1 ? 1 : 7;

        return Carbon::create((int) $year, $month, 1)->format('Y-m-d');
    }
}
