<?php

declare(strict_types=1);

namespace Kylin\Holiday\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;

/**
 * 节假日数据年度更新命令
 *
 * 每年初更新国务院发布的法定节假日安排。
 * 支持从公开 API 或本地文件导入，确保数据时效性。
 *
 * 依据《未成年人保护法》第七十五条，法定节假日需准确判断。
 *
 * 使用方式：
 *   php artisan holiday:update --year=2026
 *   php artisan holiday:update --year=2026 --source=api
 *   php artisan holiday:update --year=2026 --source=file --file=holidays_2026.json
 */
class UpdateHolidayCommand extends Command
{
    protected $signature = 'holiday:update
                            {--year= : 更新的年份，默认当前年份}
                            {--source=api : 数据来源：api（公开API） / file（本地文件）}
                            {--file= : 本地 JSON 文件路径（source=file 时必填）}
                            {--force : 强制覆盖已有数据}';

    protected $description = '更新法定节假日数据（每年需运维更新）';

    /** 公开节假日 API 地址 */
    private const API_URL = 'https://timor.tech/api/holiday/year/{year}';

    public function handle(): int
    {
        $year = (int) ($this->option('year') ?? date('Y'));
        $source = $this->option('source') ?? 'api';
        $file = $this->option('file');
        $force = $this->option('force');

        $this->info("开始更新 {$year} 年节假日数据...");

        // 检查是否已有数据
        $exists = DB::table('kh_holidays')
            ->whereYear('date', '=', $year)
            ->exists();

        if ($exists && ! $force) {
            if (! $this->confirm("{$year} 年节假日数据已存在，是否覆盖？")) {
                $this->info('操作已取消。');
                return 0;
            }
        }

        // 获取数据
        $holidays = match ($source) {
            'file' => $this->loadFromFile($file),
            'api'  => $this->loadFromApi($year),
            default => $this->loadFromApi($year),
        };

        if (empty($holidays)) {
            $this->error('未获取到节假日数据。');
            return 1;
        }

        // 写入数据库
        $this->storeHolidays($year, $holidays, $force);

        $this->info("{$year} 年节假日数据更新完成，共 " . count($holidays) . " 天。");
        $this->line('已更新缓存，无需重启服务。');

        return 0;
    }

    /**
     * 从公开 API 加载节假日数据
     */
    private function loadFromApi(int $year): array
    {
        $this->info("正在从 API 获取 {$year} 年节假日数据...");

        try {
            $response = Http::timeout(10)
                ->get(str_replace('{year}', (string) $year, self::API_URL));

            if (! $response->successful()) {
                $this->warn("API 请求失败，HTTP {$response->status()}。请尝试使用 --source=file 方式导入。");
                return [];
            }

            $data = $response->json();
            $holidays = [];

            foreach ($data['holiday'] ?? [] as $date => $info) {
                if (isset($info['holiday']) && $info['holiday'] === true) {
                    $holidays[] = [
                        'date'       => $date,
                        'name'       => $info['name'] ?? '',
                        'is_holiday' => true,
                    ];
                }
            }

            return $holidays;
        } catch (\Throwable $e) {
            $this->error("API 请求异常: {$e->getMessage()}");
            return [];
        }
    }

    /**
     * 从本地 JSON 文件加载节假日数据
     *
     * 文件格式：
     * [
     *   {"date": "2026-01-01", "name": "元旦", "is_holiday": true},
     *   {"date": "2026-01-28", "name": "除夕", "is_holiday": true},
     *   ...
     * ]
     */
    private function loadFromFile(?string $filePath): array
    {
        if (empty($filePath)) {
            $this->error('请通过 --file 参数指定 JSON 文件路径。');
            return [];
        }

        if (! file_exists($filePath)) {
            $this->error("文件不存在: {$filePath}");
            return [];
        }

        $content = file_get_contents($filePath);
        $data = json_decode($content, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            $this->error('JSON 解析失败: ' . json_last_error_msg());
            return [];
        }

        return $data;
    }

    /**
     * 存储节假日数据到数据库
     */
    private function storeHolidays(int $year, array $holidays, bool $force): void
    {
        DB::beginTransaction();

        try {
            // 如果强制覆盖，先删除该年旧数据
            if ($force) {
                DB::table('kh_holidays')
                    ->whereYear('date', '=', $year)
                    ->delete();
            }

            $inserted = 0;
            $table = DB::table('kh_holidays');

            foreach ($holidays as $holiday) {
                $date = $holiday['date'] ?? null;

                if (! $date) {
                    continue;
                }

                $row = [
                    'date'       => $date,
                    'name'       => $holiday['name'] ?? '',
                    'is_holiday' => $holiday['is_holiday'] ?? true,
                    'year'       => $year,
                    'updated_at' => now(),
                    'created_at' => now(),
                ];

                if ($force) {
                    $table->insert($row);
                    $inserted++;
                } else {
                    // 非强制模式：更新或插入
                    $table->updateOrInsert(['date' => $date], $row);
                    $inserted++;
                }
            }

            DB::commit();

            $this->info("已写入 {$inserted} 条记录。");

            // 清理相关缓存
            \Illuminate\Support\Facades\Cache::tags(['kylin-holiday'])->flush();
        } catch (\Throwable $e) {
            DB::rollBack();
            $this->error("数据写入失败: {$e->getMessage()}");
            throw $e;
        }
    }
}