<?php

namespace App\Console\Commands;

use App\Services\Stats\DimensionSyncService;
use App\Services\Stats\StatAggregatorService;
use Carbon\Carbon;
use Carbon\CarbonPeriod;
use Illuminate\Console\Command;

class StatBackfillCommand extends Command
{
    protected $signature = 'stat:backfill
        {--from= : 시작 날짜 (YYYY-MM-DD, 필수)}
        {--to= : 종료 날짜 (YYYY-MM-DD, 기본: 어제)}
        {--domain= : 특정 도메인만 집계}
        {--tenant= : 특정 테넌트만 집계}
        {--skip-monthly : 월간 집계 건너뛰기}
        {--skip-dimensions : 차원 동기화 건너뛰기}';

    protected $description = '과거 데이터 일괄 통계 집계 (백필)';

    public function handle(StatAggregatorService $aggregator, DimensionSyncService $dimensionSync): int
    {
        $from = $this->option('from');
        if (! $from) {
            $this->error('--from 옵션은 필수입니다. 예: --from=2024-01-01');

            return self::FAILURE;
        }

        $startDate = Carbon::parse($from);
        $endDate = $this->option('to')
            ? Carbon::parse($this->option('to'))
            : Carbon::yesterday();

        $domain = $this->option('domain');
        $tenantId = $this->option('tenant') ? (int) $this->option('tenant') : null;

        $totalDays = $startDate->diffInDays($endDate) + 1;

        $this->info("📊 백필 시작: {$startDate->format('Y-m-d')} ~ {$endDate->format('Y-m-d')} ({$totalDays}일)");
        if ($domain) {
            $this->info("  도메인 필터: {$domain}");
        }
        if ($tenantId) {
            $this->info("  테넌트 필터: {$tenantId}");
        }

        $totalErrors = [];
        $totalDomainsProcessed = 0;
        $startTime = microtime(true);

        // 1. 차원 테이블 동기화 (최초 1회)
        if (! $this->option('skip-dimensions')) {
            $this->info('');
            $this->info('🔄 차원 테이블 동기화...');
            try {
                $tenants = $this->getTargetTenants($tenantId);
                foreach ($tenants as $tenant) {
                    $clients = $dimensionSync->syncClients($tenant->id);
                    $products = $dimensionSync->syncProducts($tenant->id);
                    $this->line("  tenant={$tenant->id}: 고객 {$clients}건, 제품 {$products}건");
                }
            } catch (\Throwable $e) {
                $this->warn("  차원 동기화 실패: {$e->getMessage()}");
            }
        }

        // 2. 일간 집계
        $this->info('');
        $this->info('📅 일간 집계 시작...');
        $bar = $this->output->createProgressBar($totalDays);
        $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%% %elapsed:6s%/%estimated:-6s% %message%');
        $bar->setMessage('');

        $period = CarbonPeriod::create($startDate, $endDate);

        foreach ($period as $date) {
            $bar->setMessage($date->format('Y-m-d'));

            try {
                $result = $aggregator->aggregateDaily($date, $domain, $tenantId);
                $totalDomainsProcessed += $result['domains_processed'];

                if (! empty($result['errors'])) {
                    $totalErrors = array_merge($totalErrors, $result['errors']);
                }
            } catch (\Throwable $e) {
                $totalErrors[] = "daily {$date->format('Y-m-d')}: {$e->getMessage()}";
            }

            $bar->advance();
        }

        $bar->finish();
        $this->newLine();

        // 3. 월간 집계
        if (! $this->option('skip-monthly')) {
            $this->info('');
            $this->info('📆 월간 집계 시작...');

            $months = $this->getMonthRange($startDate, $endDate);
            $monthBar = $this->output->createProgressBar(count($months));

            foreach ($months as [$year, $month]) {
                $monthBar->setMessage("{$year}-".str_pad($month, 2, '0', STR_PAD_LEFT));

                try {
                    $result = $aggregator->aggregateMonthly($year, $month, $domain, $tenantId);
                    $totalDomainsProcessed += $result['domains_processed'];

                    if (! empty($result['errors'])) {
                        $totalErrors = array_merge($totalErrors, $result['errors']);
                    }
                } catch (\Throwable $e) {
                    $totalErrors[] = "monthly {$year}-{$month}: {$e->getMessage()}";
                }

                $monthBar->advance();
            }

            $monthBar->finish();
            $this->newLine();
        }

        $durationSec = round(microtime(true) - $startTime, 1);

        $this->info('');
        $this->info('✅ 백필 완료:');
        $this->info("  - 기간: {$startDate->format('Y-m-d')} ~ {$endDate->format('Y-m-d')} ({$totalDays}일)");
        $this->info("  - 처리 도메인-테넌트: {$totalDomainsProcessed}건");
        $this->info("  - 소요 시간: {$durationSec}초");

        if (! empty($totalErrors)) {
            $this->warn('  - 에러: '.count($totalErrors).'건');
            foreach (array_slice($totalErrors, 0, 20) as $error) {
                $this->error("    - {$error}");
            }
            if (count($totalErrors) > 20) {
                $this->warn('    ... 외 '.(count($totalErrors) - 20).'건');
            }

            return self::FAILURE;
        }

        return self::SUCCESS;
    }

    private function getTargetTenants(?int $tenantId): \Illuminate\Database\Eloquent\Collection
    {
        $query = \App\Models\Tenants\Tenant::where('tenant_st_code', '!=', 'none');
        if ($tenantId) {
            $query->where('id', $tenantId);
        }

        return $query->get();
    }

    private function getMonthRange(Carbon $start, Carbon $end): array
    {
        $months = [];
        $current = $start->copy()->startOfMonth();
        $endMonth = $end->copy()->startOfMonth();

        while ($current->lte($endMonth)) {
            $months[] = [$current->year, $current->month];
            $current->addMonth();
        }

        return $months;
    }
}
