<?php

namespace App\Console\Commands;

use App\Models\Tenants\Bill;
use App\Models\Tenants\ExpectedExpense;
use App\Models\Tenants\Purchase;
use App\Models\Tenants\Withdrawal;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;

/**
 * 기존 원장 데이터를 expected_expenses로 일괄 동기화
 *
 * 사용법:
 *   php artisan expense:sync                    # 전체 동기화
 *   php artisan expense:sync --type=purchase   # 매입만
 *   php artisan expense:sync --type=card       # 카드만
 *   php artisan expense:sync --type=bill       # 발행어음만
 *   php artisan expense:sync --tenant=287      # 특정 테넌트만
 *   php artisan expense:sync --dry-run         # 시뮬레이션 (실제 저장 안함)
 */
class SyncExpectedExpensesCommand extends Command
{
    protected $signature = 'expense:sync
                            {--type= : 동기화 유형 (purchase, card, bill, all)}
                            {--tenant= : 특정 테넌트 ID만 처리}
                            {--dry-run : 시뮬레이션 모드 (실제 저장 안함)}';

    protected $description = '기존 원장 데이터(매입/카드/발행어음)를 expected_expenses로 일괄 동기화';

    private int $created = 0;

    private int $updated = 0;

    private int $skipped = 0;

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

        $this->info('=== Expected Expenses 동기화 시작 ===');
        $this->info("유형: {$type}, 테넌트: ".($tenantId ?: '전체').', 모드: '.($dryRun ? 'DRY-RUN' : '실행'));
        $this->newLine();

        if ($dryRun) {
            $this->warn('⚠️  DRY-RUN 모드: 실제 데이터는 저장되지 않습니다.');
            $this->newLine();
        }

        DB::beginTransaction();

        try {
            if ($type === 'all' || $type === 'purchase') {
                $this->syncPurchases($tenantId, $dryRun);
            }

            if ($type === 'all' || $type === 'card') {
                $this->syncCardWithdrawals($tenantId, $dryRun);
            }

            if ($type === 'all' || $type === 'bill') {
                $this->syncBills($tenantId, $dryRun);
            }

            if ($dryRun) {
                DB::rollBack();
                $this->warn('DRY-RUN 완료: 롤백됨');
            } else {
                DB::commit();
                $this->info('✅ 커밋 완료');
            }
        } catch (\Exception $e) {
            DB::rollBack();
            $this->error('❌ 오류 발생: '.$e->getMessage());

            return Command::FAILURE;
        }

        $this->newLine();
        $this->info('=== 동기화 결과 ===');
        $this->table(
            ['항목', '건수'],
            [
                ['생성', $this->created],
                ['업데이트', $this->updated],
                ['스킵 (이미 존재)', $this->skipped],
                ['합계', $this->created + $this->updated + $this->skipped],
            ]
        );

        return Command::SUCCESS;
    }

    /**
     * 매입 → expected_expenses 동기화
     */
    private function syncPurchases(?int $tenantId, bool $dryRun): void
    {
        $this->info('📦 매입(purchases) 동기화 중...');

        $query = Purchase::withoutGlobalScopes()->whereNull('deleted_at');

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

        $purchases = $query->get();
        $bar = $this->output->createProgressBar($purchases->count());

        foreach ($purchases as $purchase) {
            $this->syncPurchaseToExpense($purchase, $dryRun);
            $bar->advance();
        }

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

    /**
     * 카드 출금 → expected_expenses 동기화
     */
    private function syncCardWithdrawals(?int $tenantId, bool $dryRun): void
    {
        $this->info('💳 카드(withdrawals) 동기화 중...');

        $query = Withdrawal::withoutGlobalScopes()
            ->whereNull('deleted_at')
            ->where('payment_method', 'card');

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

        $withdrawals = $query->get();
        $bar = $this->output->createProgressBar($withdrawals->count());

        foreach ($withdrawals as $withdrawal) {
            $this->syncWithdrawalToExpense($withdrawal, $dryRun);
            $bar->advance();
        }

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

    /**
     * 발행어음 → expected_expenses 동기화
     */
    private function syncBills(?int $tenantId, bool $dryRun): void
    {
        $this->info('📄 발행어음(bills) 동기화 중...');

        $query = Bill::withoutGlobalScopes()
            ->whereNull('deleted_at')
            ->where('bill_type', 'issued'); // 발행어음만 (수령어음 제외)

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

        $bills = $query->get();
        $bar = $this->output->createProgressBar($bills->count());

        foreach ($bills as $bill) {
            $this->syncBillToExpense($bill, $dryRun);
            $bar->advance();
        }

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

    /**
     * 매입 레코드 → expected_expense 동기화
     */
    private function syncPurchaseToExpense(Purchase $purchase, bool $dryRun): void
    {
        $existing = ExpectedExpense::withoutGlobalScopes()
            ->where('source_type', 'purchases')
            ->where('source_id', $purchase->id)
            ->first();

        if ($existing) {
            // 이미 존재하면 업데이트
            if (! $dryRun) {
                $existing->update([
                    'expected_payment_date' => $purchase->purchase_date,
                    'amount' => $purchase->total_amount,
                    'client_id' => $purchase->client_id,
                    'description' => $purchase->description ?? "매입번호: {$purchase->purchase_number}",
                    'payment_status' => $purchase->withdrawal_id ? 'paid' : 'pending',
                    'updated_by' => $purchase->updated_by,
                ]);
            }
            $this->updated++;
        } else {
            // 새로 생성
            if (! $dryRun) {
                ExpectedExpense::create([
                    'tenant_id' => $purchase->tenant_id,
                    'expected_payment_date' => $purchase->purchase_date,
                    'transaction_type' => 'purchase',
                    'amount' => $purchase->total_amount,
                    'client_id' => $purchase->client_id,
                    'description' => $purchase->description ?? "매입번호: {$purchase->purchase_number}",
                    'payment_status' => $purchase->withdrawal_id ? 'paid' : 'pending',
                    'approval_status' => 'none',
                    'source_type' => 'purchases',
                    'source_id' => $purchase->id,
                    'created_by' => $purchase->created_by,
                    'updated_by' => $purchase->updated_by,
                ]);
            }
            $this->created++;
        }
    }

    /**
     * 카드 출금 레코드 → expected_expense 동기화
     */
    private function syncWithdrawalToExpense(Withdrawal $withdrawal, bool $dryRun): void
    {
        $existing = ExpectedExpense::withoutGlobalScopes()
            ->where('source_type', 'withdrawals')
            ->where('source_id', $withdrawal->id)
            ->first();

        $clientName = $withdrawal->client_name ?: $withdrawal->merchant_name ?: '미지정';

        if ($existing) {
            if (! $dryRun) {
                $existing->update([
                    'expected_payment_date' => $withdrawal->withdrawal_date ?? $withdrawal->used_at,
                    'amount' => $withdrawal->amount,
                    'client_id' => $withdrawal->client_id,
                    'description' => $withdrawal->description ?? "카드결제: {$clientName}",
                    'payment_status' => 'paid', // 카드는 이미 결제됨
                    'updated_by' => $withdrawal->updated_by,
                ]);
            }
            $this->updated++;
        } else {
            if (! $dryRun) {
                ExpectedExpense::create([
                    'tenant_id' => $withdrawal->tenant_id,
                    'expected_payment_date' => $withdrawal->withdrawal_date ?? $withdrawal->used_at,
                    'transaction_type' => 'card',
                    'amount' => $withdrawal->amount,
                    'client_id' => $withdrawal->client_id,
                    'description' => $withdrawal->description ?? "카드결제: {$clientName}",
                    'payment_status' => 'paid',
                    'approval_status' => 'none',
                    'source_type' => 'withdrawals',
                    'source_id' => $withdrawal->id,
                    'created_by' => $withdrawal->created_by,
                    'updated_by' => $withdrawal->updated_by,
                ]);
            }
            $this->created++;
        }
    }

    /**
     * 발행어음 레코드 → expected_expense 동기화
     */
    private function syncBillToExpense(Bill $bill, bool $dryRun): void
    {
        $existing = ExpectedExpense::withoutGlobalScopes()
            ->where('source_type', 'bills')
            ->where('source_id', $bill->id)
            ->first();

        $clientName = $bill->client_name ?: '미지정';

        if ($existing) {
            if (! $dryRun) {
                $existing->update([
                    'expected_payment_date' => $bill->maturity_date, // 만기일 기준
                    'amount' => $bill->amount,
                    'client_id' => $bill->client_id,
                    'description' => $bill->note ?? "발행어음: {$bill->bill_number}",
                    'payment_status' => $bill->status === 'settled' ? 'paid' : 'pending',
                    'updated_by' => $bill->updated_by,
                ]);
            }
            $this->updated++;
        } else {
            if (! $dryRun) {
                ExpectedExpense::create([
                    'tenant_id' => $bill->tenant_id,
                    'expected_payment_date' => $bill->maturity_date,
                    'transaction_type' => 'bill',
                    'amount' => $bill->amount,
                    'client_id' => $bill->client_id,
                    'description' => $bill->note ?? "발행어음: {$bill->bill_number}",
                    'payment_status' => $bill->status === 'settled' ? 'paid' : 'pending',
                    'approval_status' => 'none',
                    'source_type' => 'bills',
                    'source_id' => $bill->id,
                    'created_by' => $bill->created_by,
                    'updated_by' => $bill->updated_by,
                ]);
            }
            $this->created++;
        }
    }
}
