<?php

namespace App\Http\Controllers\Finance;

use App\Http\Controllers\Controller;
use App\Models\Barobill\CardTransaction as BarobillCardTransaction;
use App\Models\Barobill\CardTransactionHide;
use App\Models\Barobill\CardTransactionSplit;
use App\Models\Barobill\HometaxInvoice;
use App\Models\Finance\VatRecord;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class VatRecordController extends Controller
{
    public function index(Request $request): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        $period = $request->input('period');

        // Step 1: 기간 → 날짜 범위 변환
        [$startDate, $endDate] = $period ? $this->periodToDateRange($period) : [null, null];
        $startDateYmd = $startDate ? str_replace('-', '', $startDate) : null;
        $endDateYmd = $endDate ? str_replace('-', '', $endDate) : null;

        $taxTypeMap = [
            1 => 'taxable',
            2 => 'zero_rated',
            3 => 'exempt',
        ];

        // Step 2: 홈택스 매출 조회
        $hometaxSalesRecords = collect();
        $hometaxPurchaseRecords = collect();
        $cardRecords = collect();

        if ($startDate && $endDate) {
            // 홈택스 매출
            $hometaxSales = HometaxInvoice::where('tenant_id', $tenantId)
                ->sales()
                ->period($startDate, $endDate)
                ->get();

            $hometaxSalesRecords = $hometaxSales->map(function ($inv) use ($period, $taxTypeMap) {
                return [
                    'id' => 'hometax_'.$inv->id,
                    'period' => $period,
                    'type' => 'sales',
                    'taxType' => $taxTypeMap[$inv->tax_type] ?? 'taxable',
                    'partnerName' => $inv->invoicee_corp_name,
                    'invoiceNo' => $inv->nts_confirm_num ?? '',
                    'invoiceDate' => $inv->write_date ? \Carbon\Carbon::parse($inv->write_date)->format('Y-m-d') : null,
                    'supplyAmount' => (int) $inv->supply_amount,
                    'vatAmount' => (int) $inv->tax_amount,
                    'totalAmount' => (int) $inv->total_amount,
                    'status' => 'filed',
                    'memo' => null,
                    'isCardTransaction' => false,
                    'isHometax' => true,
                    'source' => 'hometax',
                ];
            });

            // Step 3: 홈택스 매입 조회
            $hometaxPurchases = HometaxInvoice::where('tenant_id', $tenantId)
                ->purchase()
                ->period($startDate, $endDate)
                ->get();

            $hometaxPurchaseRecords = $hometaxPurchases->map(function ($inv) use ($period, $taxTypeMap) {
                return [
                    'id' => 'hometax_'.$inv->id,
                    'period' => $period,
                    'type' => 'purchase',
                    'taxType' => $taxTypeMap[$inv->tax_type] ?? 'taxable',
                    'partnerName' => $inv->invoicer_corp_name,
                    'invoiceNo' => $inv->nts_confirm_num ?? '',
                    'invoiceDate' => $inv->write_date ? \Carbon\Carbon::parse($inv->write_date)->format('Y-m-d') : null,
                    'supplyAmount' => (int) $inv->supply_amount,
                    'vatAmount' => (int) $inv->tax_amount,
                    'totalAmount' => (int) $inv->total_amount,
                    'status' => 'filed',
                    'memo' => null,
                    'isCardTransaction' => false,
                    'isHometax' => true,
                    'source' => 'hometax',
                ];
            });

            // Step 4: 카드 공제분 조회
            if ($startDateYmd && $endDateYmd) {
                $hiddenKeys = CardTransactionHide::getHiddenKeys($tenantId, $startDateYmd, $endDateYmd);

                $cardTransactions = BarobillCardTransaction::where('tenant_id', $tenantId)
                    ->whereBetween('use_date', [$startDateYmd, $endDateYmd])
                    ->orderBy('use_date', 'desc')
                    ->get();

                $splitsByKey = CardTransactionSplit::getByDateRange($tenantId, $startDateYmd, $endDateYmd);

                // 분개가 존재하는 거래의 부분키(금액 제외) 인덱스 생성
                // 수동입력 등으로 금액이 달라져도 매칭되도록 함
                $splitsByPartialKey = [];
                foreach ($splitsByKey as $fullKey => $splits) {
                    $parts = explode('|', $fullKey);
                    if (count($parts) >= 3) {
                        $partialKey = $parts[0].'|'.$parts[1].'|'.$parts[2];
                        $splitsByPartialKey[$partialKey] = $splits;
                    }
                }

                foreach ($cardTransactions as $card) {
                    // 숨김 처리된 거래는 skip
                    if ($hiddenKeys->contains($card->unique_key)) {
                        continue;
                    }

                    // 분개 매칭: 정확한 키 → 부분키(금액 제외) 순으로 시도
                    $splits = $splitsByKey[$card->unique_key] ?? null;
                    if (! $splits) {
                        $cardPartialKey = $card->card_num.'|'.$card->use_dt.'|'.$card->approval_num;
                        $splits = $splitsByPartialKey[$cardPartialKey] ?? null;
                    }

                    if ($splits && count($splits) > 0) {
                        // 분개가 있으면: deductible 분개만 포함
                        foreach ($splits as $split) {
                            if ($split->deduction_type === 'deductible') {
                                $cardRecords->push([
                                    'id' => 'card_split_'.$split->id,
                                    'period' => $period,
                                    'type' => 'purchase',
                                    'taxType' => 'taxable',
                                    'partnerName' => $card->merchant_name,
                                    'invoiceNo' => $card->approval_num ?? '',
                                    'invoiceDate' => $card->use_date ? \Carbon\Carbon::createFromFormat('Ymd', $card->use_date)->format('Y-m-d') : null,
                                    'supplyAmount' => (int) $split->split_supply_amount,
                                    'vatAmount' => (int) $split->split_tax,
                                    'totalAmount' => (int) $split->split_amount,
                                    'status' => 'filed',
                                    'memo' => $split->account_name ?? null,
                                    'isCardTransaction' => true,
                                    'isHometax' => false,
                                    'source' => 'card',
                                ]);
                            }
                        }
                    } else {
                        // 분개가 없으면: deduction_type='deductible'인 경우만 포함
                        if ($card->deduction_type === 'deductible') {
                            $effectiveSupply = $card->modified_supply_amount
                                ?? ($card->approval_amount - $card->tax);
                            $effectiveTax = $card->modified_tax ?? $card->tax;

                            $cardRecords->push([
                                'id' => 'card_'.$card->id,
                                'period' => $period,
                                'type' => 'purchase',
                                'taxType' => 'taxable',
                                'partnerName' => $card->merchant_name,
                                'invoiceNo' => $card->approval_num ?? '',
                                'invoiceDate' => $card->use_date ? \Carbon\Carbon::createFromFormat('Ymd', $card->use_date)->format('Y-m-d') : null,
                                'supplyAmount' => (int) $effectiveSupply,
                                'vatAmount' => (int) $effectiveTax,
                                'totalAmount' => (int) ($effectiveSupply + $effectiveTax),
                                'status' => 'filed',
                                'memo' => $card->memo,
                                'isCardTransaction' => true,
                                'isHometax' => false,
                                'source' => 'card',
                            ]);
                        }
                    }
                }
            }
        }

        // Step 5: 수동 입력 (vat_records) - 기존 유지
        $manualQuery = VatRecord::forTenant($tenantId);

        if ($period) {
            $manualQuery->where('period', $period);
        }

        $manualRecords = $manualQuery->orderBy('invoice_date', 'desc')
            ->get()
            ->map(function ($record) {
                return [
                    'id' => $record->id,
                    'period' => $record->period,
                    'type' => $record->type,
                    'taxType' => $record->tax_type ?? 'taxable',
                    'partnerName' => $record->partner_name,
                    'invoiceNo' => $record->invoice_no,
                    'invoiceDate' => $record->invoice_date?->format('Y-m-d'),
                    'supplyAmount' => $record->supply_amount,
                    'vatAmount' => $record->vat_amount,
                    'totalAmount' => $record->total_amount,
                    'status' => $record->status,
                    'memo' => $record->memo,
                    'isCardTransaction' => false,
                    'isHometax' => false,
                    'source' => 'manual',
                ];
            });

        // Step 6: 통합 및 통계
        $allRecords = $hometaxSalesRecords
            ->concat($hometaxPurchaseRecords)
            ->concat($cardRecords)
            ->concat($manualRecords)
            ->values();

        // 홈택스 매출 전자세금계산서 (과세 + 영세만, 면세 제외)
        $hometaxSalesTaxable = $hometaxSalesRecords->whereIn('taxType', ['taxable', 'zero_rated']);
        $hometaxSalesSupply = $hometaxSalesTaxable->sum('supplyAmount');
        $hometaxSalesVat = $hometaxSalesTaxable->sum('vatAmount');

        // 홈택스 매입 전자세금계산서 (과세 + 영세만, 면세 제외)
        $hometaxPurchaseTaxable = $hometaxPurchaseRecords->whereIn('taxType', ['taxable', 'zero_rated']);
        $hometaxPurchaseSupply = $hometaxPurchaseTaxable->sum('supplyAmount');
        $hometaxPurchaseVat = $hometaxPurchaseTaxable->sum('vatAmount');

        // 홈택스 면세 계산서 (매입 + 매출 모두)
        $exemptSalesSupply = $hometaxSalesRecords->where('taxType', 'exempt')->sum('supplyAmount');
        $exemptPurchaseSupply = $hometaxPurchaseRecords->where('taxType', 'exempt')->sum('supplyAmount');

        // 카드 매입
        $cardPurchaseSupply = $cardRecords->sum('supplyAmount');
        $cardPurchaseVat = $cardRecords->sum('vatAmount');

        // 수동입력 매입 종이세금계산서 (과세+영세)
        $manualPurchaseTaxable = $manualRecords->where('type', 'purchase')->whereIn('taxType', ['taxable', 'zero_rated']);
        $manualPurchaseSupply = $manualPurchaseTaxable->sum('supplyAmount');
        $manualPurchaseVat = $manualPurchaseTaxable->sum('vatAmount');

        // 수동입력 면세 계산서
        $manualExemptSalesSupply = $manualRecords->where('type', 'sales')->where('taxType', 'exempt')->sum('supplyAmount');
        $manualExemptPurchaseSupply = $manualRecords->where('type', 'purchase')->where('taxType', 'exempt')->sum('supplyAmount');

        // 면세 계산서 합계 (홈택스 + 수동)
        $exemptSupply = $exemptSalesSupply + $exemptPurchaseSupply + $manualExemptSalesSupply + $manualExemptPurchaseSupply;

        $stats = [
            'salesSupply' => $hometaxSalesSupply,
            'salesVat' => $hometaxSalesVat,
            'purchaseSupply' => $hometaxPurchaseSupply + $cardPurchaseSupply + $manualPurchaseSupply,
            'purchaseVat' => $hometaxPurchaseVat + $cardPurchaseVat + $manualPurchaseVat,
            'hometaxSalesSupply' => $hometaxSalesSupply,
            'hometaxSalesVat' => $hometaxSalesVat,
            'hometaxPurchaseSupply' => $hometaxPurchaseSupply,
            'hometaxPurchaseVat' => $hometaxPurchaseVat,
            'manualPurchaseSupply' => $manualPurchaseSupply,
            'manualPurchaseVat' => $manualPurchaseVat,
            'exemptSupply' => $exemptSupply,
            'cardPurchaseSupply' => $cardPurchaseSupply,
            'cardPurchaseVat' => $cardPurchaseVat,
            'total' => $allRecords->count(),
            'preliminaryVat' => null,
        ];

        // 확정(C) 기간이면 대응하는 예정(P)의 netVat를 계산
        if ($period && str_ends_with($period, 'C')) {
            try {
                $prelimPeriod = substr($period, 0, -1).'P';
                $stats['preliminaryVat'] = $this->calculatePeriodNetVat($tenantId, $prelimPeriod);
            } catch (\Throwable $e) {
                \Log::error('예정 세액 계산 실패', [
                    'message' => $e->getMessage(),
                    'file' => $e->getFile().':'.$e->getLine(),
                    'trace' => array_slice(array_map(fn ($t) => ($t['file'] ?? '').':'.($t['line'] ?? '').' '.($t['function'] ?? ''), $e->getTrace()), 0, 5),
                    'tenant_id' => $tenantId,
                    'period' => $prelimPeriod ?? null,
                ]);
                $stats['preliminaryVat'] = null;
            }
        }

        // 사용 중인 기간 목록
        $periods = VatRecord::forTenant($tenantId)
            ->select('period')
            ->distinct()
            ->orderBy('period', 'desc')
            ->pluck('period')
            ->toArray();

        return response()->json([
            'success' => true,
            'data' => $allRecords,
            'stats' => $stats,
            'periods' => $periods,
        ]);
    }

    public function store(Request $request): JsonResponse
    {
        $request->validate([
            'partnerName' => 'required|string|max:100',
            'period' => 'required|string|max:20',
            'type' => 'required|in:sales,purchase',
            'taxType' => 'nullable|in:taxable,zero_rated,exempt',
            'supplyAmount' => 'required|integer|min:0',
        ]);

        $tenantId = session('selected_tenant_id', 1);

        $record = VatRecord::create([
            'tenant_id' => $tenantId,
            'period' => $request->input('period'),
            'type' => $request->input('type', 'sales'),
            'tax_type' => $request->input('taxType', 'taxable'),
            'partner_name' => $request->input('partnerName'),
            'invoice_no' => $request->input('invoiceNo'),
            'invoice_date' => $request->input('invoiceDate'),
            'supply_amount' => $request->input('supplyAmount', 0),
            'vat_amount' => $request->input('vatAmount', 0),
            'total_amount' => $request->input('totalAmount', 0),
            'status' => $request->input('status', 'pending'),
            'memo' => $request->input('memo'),
        ]);

        return response()->json([
            'success' => true,
            'message' => '세금계산서가 등록되었습니다.',
            'data' => ['id' => $record->id],
        ]);
    }

    public function update(Request $request, int $id): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        $record = VatRecord::forTenant($tenantId)->findOrFail($id);

        $request->validate([
            'partnerName' => 'required|string|max:100',
            'period' => 'required|string|max:20',
            'type' => 'required|in:sales,purchase',
            'taxType' => 'nullable|in:taxable,zero_rated,exempt',
            'supplyAmount' => 'required|integer|min:0',
        ]);

        $record->update([
            'period' => $request->input('period'),
            'type' => $request->input('type'),
            'tax_type' => $request->input('taxType', $record->tax_type),
            'partner_name' => $request->input('partnerName'),
            'invoice_no' => $request->input('invoiceNo'),
            'invoice_date' => $request->input('invoiceDate'),
            'supply_amount' => $request->input('supplyAmount', 0),
            'vat_amount' => $request->input('vatAmount', 0),
            'total_amount' => $request->input('totalAmount', 0),
            'status' => $request->input('status'),
            'memo' => $request->input('memo'),
        ]);

        return response()->json([
            'success' => true,
            'message' => '세금계산서가 수정되었습니다.',
        ]);
    }

    public function destroy(int $id): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        $record = VatRecord::forTenant($tenantId)->findOrFail($id);
        $record->delete();

        return response()->json([
            'success' => true,
            'message' => '세금계산서가 삭제되었습니다.',
        ]);
    }

    /**
     * 특정 기간의 순 부가세 계산 (매출세액 - 매입세액)
     * 양수: 납부세액, 음수: 환급세액
     */
    private function calculatePeriodNetVat(int $tenantId, string $period): int
    {
        [$startDate, $endDate] = $this->periodToDateRange($period);
        if (! $startDate || ! $endDate) {
            return 0;
        }

        $startDateYmd = str_replace('-', '', $startDate);
        $endDateYmd = str_replace('-', '', $endDate);

        $taxTypeMap = [1 => 'taxable', 2 => 'zero_rated', 3 => 'exempt'];

        // 홈택스 매출세액 (과세+영세)
        $salesVat = (int) HometaxInvoice::where('tenant_id', $tenantId)
            ->sales()
            ->period($startDate, $endDate)
            ->whereIn('tax_type', [1, 2])
            ->sum('tax_amount');

        // 홈택스 매입세액 (과세+영세)
        $purchaseVat = (int) HometaxInvoice::where('tenant_id', $tenantId)
            ->purchase()
            ->period($startDate, $endDate)
            ->whereIn('tax_type', [1, 2])
            ->sum('tax_amount');

        // 카드 매입세액 (공제분만)
        $cardVat = 0;
        $hiddenKeys = CardTransactionHide::getHiddenKeys($tenantId, $startDateYmd, $endDateYmd);

        $cardTransactions = BarobillCardTransaction::where('tenant_id', $tenantId)
            ->whereBetween('use_date', [$startDateYmd, $endDateYmd])
            ->get();

        $splitsByKey = CardTransactionSplit::getByDateRange($tenantId, $startDateYmd, $endDateYmd);

        $splitsByPartialKey = [];
        foreach ($splitsByKey as $fullKey => $splits) {
            $parts = explode('|', $fullKey);
            if (count($parts) >= 3) {
                $partialKey = $parts[0].'|'.$parts[1].'|'.$parts[2];
                $splitsByPartialKey[$partialKey] = $splits;
            }
        }

        foreach ($cardTransactions as $card) {
            if ($hiddenKeys->contains($card->unique_key)) {
                continue;
            }

            $splits = $splitsByKey[$card->unique_key] ?? null;
            if (! $splits) {
                $cardPartialKey = $card->card_num.'|'.$card->use_dt.'|'.$card->approval_num;
                $splits = $splitsByPartialKey[$cardPartialKey] ?? null;
            }

            if ($splits && count($splits) > 0) {
                foreach ($splits as $split) {
                    if ($split->deduction_type === 'deductible') {
                        $cardVat += (int) $split->split_tax;
                    }
                }
            } else {
                if ($card->deduction_type === 'deductible') {
                    $cardVat += (int) ($card->modified_tax ?? $card->tax);
                }
            }
        }

        // 수동입력 세액 (면세 제외한 과세+영세만 합산, index와 동일하게 인메모리 필터링)
        $manualRecords = VatRecord::forTenant($tenantId)
            ->where('period', $period)
            ->get();

        $manualSalesVat = (int) $manualRecords
            ->where('type', 'sales')
            ->whereIn('tax_type', ['taxable', 'zero_rated', null])
            ->sum('vat_amount');

        $manualPurchaseVat = (int) $manualRecords
            ->where('type', 'purchase')
            ->whereIn('tax_type', ['taxable', 'zero_rated', null])
            ->sum('vat_amount');

        $totalSalesVat = $salesVat + $manualSalesVat;
        $totalPurchaseVat = $purchaseVat + $cardVat + $manualPurchaseVat;

        return $totalSalesVat - $totalPurchaseVat;
    }

    /**
     * 부가세 신고기간을 날짜 범위로 변환
     * YYYY-1P: 1기 예정 (0101~0331)
     * YYYY-1C: 1기 확정 (0401~0630)
     * YYYY-2P: 2기 예정 (0701~0930)
     * YYYY-2C: 2기 확정 (1001~1231)
     */
    private function periodToDateRange(string $period): array
    {
        $parts = explode('-', $period);
        if (count($parts) !== 2) {
            return [null, null];
        }

        $year = $parts[0];
        $code = $parts[1];

        $ranges = [
            '1P' => ["{$year}-01-01", "{$year}-03-31"],
            '1C' => ["{$year}-04-01", "{$year}-06-30"],
            '2P' => ["{$year}-07-01", "{$year}-09-30"],
            '2C' => ["{$year}-10-01", "{$year}-12-31"],
        ];

        return $ranges[$code] ?? [null, null];
    }
}
