<?php

namespace App\Console\Commands;

use App\Models\Boards\File;
use App\Models\Tenants\Tenant;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

/**
 * 테넌트 저장소 사용량 재계산 명령어
 *
 * files 테이블의 실제 file_size 합계로 tenants.storage_used를 업데이트합니다.
 *
 * @example php artisan tenant:recalculate-storage
 * @example php artisan tenant:recalculate-storage --tenant=1
 * @example php artisan tenant:recalculate-storage --dry-run
 */
class RecalculateTenantStorageCommand extends Command
{
    protected $signature = 'tenant:recalculate-storage
                            {--tenant= : 특정 테넌트 ID만 처리}
                            {--dry-run : 실제 업데이트 없이 결과만 확인}';

    protected $description = '테넌트별 저장소 사용량을 files 테이블 기준으로 재계산합니다';

    public function handle(): int
    {
        $tenantId = $this->option('tenant');
        $dryRun = $this->option('dry-run');

        $this->info('');
        $this->info('===========================================');
        $this->info('  테넌트 저장소 사용량 재계산');
        $this->info('===========================================');

        if ($dryRun) {
            $this->warn('  [DRY-RUN 모드] 실제 업데이트가 수행되지 않습니다.');
        }

        $this->info('');

        // 테넌트별 실제 파일 사용량 계산
        $query = File::query()
            ->select('tenant_id', DB::raw('SUM(file_size) as total_size'), DB::raw('COUNT(*) as file_count'))
            ->whereNotNull('tenant_id')
            ->groupBy('tenant_id');

        if ($tenantId) {
            $query->where('tenant_id', $tenantId);
        }

        $actualUsage = $query->get()->keyBy('tenant_id');

        // 모든 테넌트 조회
        $tenantsQuery = Tenant::query();
        if ($tenantId) {
            $tenantsQuery->where('id', $tenantId);
        }
        $tenants = $tenantsQuery->get();

        if ($tenants->isEmpty()) {
            $this->warn('처리할 테넌트가 없습니다.');

            return Command::SUCCESS;
        }

        $results = [];
        $updated = 0;
        $errors = 0;

        foreach ($tenants as $tenant) {
            $currentStored = $tenant->storage_used ?? 0;
            $actualData = $actualUsage->get($tenant->id);
            $actualSize = $actualData?->total_size ?? 0;
            $fileCount = $actualData?->file_count ?? 0;
            $difference = $actualSize - $currentStored;

            $status = '✅ 정상';
            if ($difference !== 0) {
                $status = $difference > 0 ? '⚠️ 부족' : '⚠️ 초과';
            }

            $results[] = [
                $tenant->id,
                $tenant->company_name ?? 'N/A',
                $fileCount,
                $this->formatBytes($currentStored),
                $this->formatBytes($actualSize),
                $this->formatDifference($difference),
                $status,
            ];

            // 업데이트 필요 시
            if ($difference !== 0 && ! $dryRun) {
                try {
                    $tenant->storage_used = $actualSize;
                    $tenant->save();
                    $updated++;
                } catch (\Exception $e) {
                    $this->error("테넌트 {$tenant->id} 업데이트 실패: {$e->getMessage()}");
                    $errors++;
                }
            }
        }

        // 결과 테이블 출력
        $this->table(
            ['ID', '회사명', '파일수', '저장된 값', '실제 값', '차이', '상태'],
            $results
        );

        $this->info('');
        $this->info('===========================================');
        $this->info("  총 테넌트: {$tenants->count()}개");

        if ($dryRun) {
            $needsUpdate = collect($results)->filter(fn ($r) => $r[6] !== '✅ 정상')->count();
            $this->warn("  업데이트 필요: {$needsUpdate}개");
            $this->info('  [DRY-RUN] 실제 업데이트를 수행하려면 --dry-run 옵션을 제거하세요.');
        } else {
            $this->info("  업데이트됨: {$updated}개");
            if ($errors > 0) {
                $this->error("  실패: {$errors}개");
            }
        }
        $this->info('===========================================');
        $this->info('');

        return $errors > 0 ? Command::FAILURE : Command::SUCCESS;
    }

    /**
     * 바이트를 읽기 쉬운 형식으로 변환
     */
    private function formatBytes(int $bytes): string
    {
        if ($bytes >= 1073741824) {
            return number_format($bytes / 1073741824, 2).' GB';
        } elseif ($bytes >= 1048576) {
            return number_format($bytes / 1048576, 2).' MB';
        } elseif ($bytes >= 1024) {
            return number_format($bytes / 1024, 2).' KB';
        }

        return number_format($bytes).' B';
    }

    /**
     * 차이값 포맷팅 (양수/음수 표시)
     */
    private function formatDifference(int $diff): string
    {
        if ($diff === 0) {
            return '0';
        }

        $prefix = $diff > 0 ? '+' : '';
        $absBytes = abs($diff);

        return $prefix.$this->formatBytes($absBytes);
    }
}
