<?php

namespace App\Services;

use App\Models\Tenants\TaxInvoice;
use Carbon\Carbon;

/**
 * 부가세 현황 서비스
 *
 * CEO 대시보드용 부가세 데이터를 제공합니다.
 */
class VatService extends Service
{
    /**
     * 부가세 현황 요약 조회
     *
     * @param  string|null  $periodType  기간 타입 (quarter|half|year, 기본: quarter)
     * @param  int|null  $year  연도 (기본: 현재 연도)
     * @param  int|null  $period  기간 번호 (quarter: 1-4, half: 1-2, 기본: 현재 기간)
     * @return array{cards: array, check_points: array}
     */
    public function getSummary(?string $periodType = 'quarter', ?int $year = null, ?int $period = null): array
    {
        $tenantId = $this->tenantId();
        $now = Carbon::now();

        // 기본값 설정
        $year = $year ?? $now->year;
        $periodType = $periodType ?? 'quarter';
        $period = $period ?? $this->getCurrentPeriod($periodType, $now);

        // 기간 범위 계산
        [$startDate, $endDate] = $this->getPeriodDateRange($year, $periodType, $period);

        // 발행 완료된 세금계산서만 계산 (status: issued, sent)
        $validStatuses = [TaxInvoice::STATUS_ISSUED, TaxInvoice::STATUS_SENT];

        // 매출세액 (sales)
        $salesTaxAmount = TaxInvoice::where('tenant_id', $tenantId)
            ->where('direction', TaxInvoice::DIRECTION_SALES)
            ->whereIn('status', $validStatuses)
            ->whereBetween('issue_date', [$startDate, $endDate])
            ->sum('tax_amount');

        // 매입세액 (purchases)
        $purchasesTaxAmount = TaxInvoice::where('tenant_id', $tenantId)
            ->where('direction', TaxInvoice::DIRECTION_PURCHASES)
            ->whereIn('status', $validStatuses)
            ->whereBetween('issue_date', [$startDate, $endDate])
            ->sum('tax_amount');

        // 예상 납부세액 (매출세액 - 매입세액)
        $estimatedPayment = $salesTaxAmount - $purchasesTaxAmount;

        // 미발행 세금계산서 건수 (전체 기간, status: draft)
        $unissuedCount = TaxInvoice::where('tenant_id', $tenantId)
            ->where('status', TaxInvoice::STATUS_DRAFT)
            ->count();

        // 카드 데이터 구성
        $cards = [
            [
                'id' => 'vat_sales_tax',
                'label' => '매출세액',
                'amount' => (int) $salesTaxAmount,
            ],
            [
                'id' => 'vat_purchases_tax',
                'label' => '매입세액',
                'amount' => (int) $purchasesTaxAmount,
            ],
            [
                'id' => 'vat_estimated_payment',
                'label' => '예상 납부세액',
                'amount' => (int) abs($estimatedPayment),
                'subLabel' => $estimatedPayment < 0 ? '환급' : null,
            ],
            [
                'id' => 'vat_unissued',
                'label' => '세금계산서 미발행',
                'amount' => $unissuedCount,
                'unit' => '건',
            ],
        ];

        // 체크포인트 생성
        $checkPoints = $this->generateCheckPoints(
            $year,
            $periodType,
            $period,
            $salesTaxAmount,
            $purchasesTaxAmount,
            $estimatedPayment,
            $tenantId
        );

        return [
            'cards' => $cards,
            'check_points' => $checkPoints,
        ];
    }

    /**
     * 현재 기간 계산
     */
    private function getCurrentPeriod(string $periodType, Carbon $date): int
    {
        return match ($periodType) {
            'quarter' => $date->quarter,
            'half' => $date->month <= 6 ? 1 : 2,
            'year' => 1,
            default => $date->quarter,
        };
    }

    /**
     * 기간 범위 날짜 계산
     *
     * @return array{0: string, 1: string} [startDate, endDate]
     */
    private function getPeriodDateRange(int $year, string $periodType, int $period): array
    {
        return match ($periodType) {
            'quarter' => [
                Carbon::create($year, ($period - 1) * 3 + 1, 1)->format('Y-m-d'),
                Carbon::create($year, $period * 3, 1)->endOfMonth()->format('Y-m-d'),
            ],
            'half' => [
                Carbon::create($year, ($period - 1) * 6 + 1, 1)->format('Y-m-d'),
                Carbon::create($year, $period * 6, 1)->endOfMonth()->format('Y-m-d'),
            ],
            'year' => [
                Carbon::create($year, 1, 1)->format('Y-m-d'),
                Carbon::create($year, 12, 31)->format('Y-m-d'),
            ],
            default => [
                Carbon::create($year, ($period - 1) * 3 + 1, 1)->format('Y-m-d'),
                Carbon::create($year, $period * 3, 1)->endOfMonth()->format('Y-m-d'),
            ],
        };
    }

    /**
     * 체크포인트 생성
     */
    private function generateCheckPoints(
        int $year,
        string $periodType,
        int $period,
        float $salesTaxAmount,
        float $purchasesTaxAmount,
        float $estimatedPayment,
        int $tenantId
    ): array {
        $checkPoints = [];
        $periodLabel = $this->getPeriodLabel($year, $periodType, $period);

        // 이전 기간 데이터 조회 (전기 대비 비교용)
        $previousPeriod = $this->getPreviousPeriod($year, $periodType, $period);
        [$prevStartDate, $prevEndDate] = $this->getPeriodDateRange(
            $previousPeriod['year'],
            $periodType,
            $previousPeriod['period']
        );

        $validStatuses = [TaxInvoice::STATUS_ISSUED, TaxInvoice::STATUS_SENT];

        $prevSalesTax = TaxInvoice::where('tenant_id', $tenantId)
            ->where('direction', TaxInvoice::DIRECTION_SALES)
            ->whereIn('status', $validStatuses)
            ->whereBetween('issue_date', [$prevStartDate, $prevEndDate])
            ->sum('tax_amount');

        $prevPurchasesTax = TaxInvoice::where('tenant_id', $tenantId)
            ->where('direction', TaxInvoice::DIRECTION_PURCHASES)
            ->whereIn('status', $validStatuses)
            ->whereBetween('issue_date', [$prevStartDate, $prevEndDate])
            ->sum('tax_amount');

        $prevEstimatedPayment = $prevSalesTax - $prevPurchasesTax;

        // 납부/환급 여부에 따른 메시지 생성
        if ($estimatedPayment < 0) {
            // 환급
            $refundAmount = number_format(abs($estimatedPayment));
            $message = "{$periodLabel} 기준, 예상 환급세액은 {$refundAmount}원입니다.";

            // 원인 분석 추가
            if ($purchasesTaxAmount > $salesTaxAmount) {
                $message .= ' 매입세액이 매출세액을 초과하여 환급이 예상됩니다.';
            }

            $checkPoints[] = [
                'id' => 'vat_cp_refund',
                'type' => 'success',
                'message' => $message,
                'highlights' => [
                    ['text' => "{$periodLabel} 기준, 예상 환급세액은 {$refundAmount}원입니다.", 'color' => 'blue'],
                ],
            ];
        } else {
            // 납부
            $paymentAmount = number_format($estimatedPayment);
            $message = "{$periodLabel} 기준, 예상 납부세액은 {$paymentAmount}원입니다.";

            // 전기 대비 변동률 계산
            if ($prevEstimatedPayment > 0) {
                $changeRate = (($estimatedPayment - $prevEstimatedPayment) / $prevEstimatedPayment) * 100;
                $changeDirection = $changeRate >= 0 ? '증가' : '감소';
                $message .= sprintf(' 전기 대비 %.1f%% %s했습니다.', abs($changeRate), $changeDirection);
            }

            $checkPoints[] = [
                'id' => 'vat_cp_payment',
                'type' => 'success',
                'message' => $message,
                'highlights' => [
                    ['text' => "{$periodLabel} 기준, 예상 납부세액은 {$paymentAmount}원입니다.", 'color' => 'red'],
                ],
            ];
        }

        return $checkPoints;
    }

    /**
     * 기간 라벨 생성
     */
    private function getPeriodLabel(int $year, string $periodType, int $period): string
    {
        return match ($periodType) {
            'quarter' => "{$year}년 {$period}기 예정신고",
            'half' => "{$year}년 ".($period === 1 ? '상반기' : '하반기').' 확정신고',
            'year' => "{$year}년 연간",
            default => "{$year}년 {$period}기",
        };
    }

    /**
     * 부가세 상세 조회 (모달용)
     *
     * @param  string|null  $periodType  기간 타입 (quarter|half|year)
     * @param  int|null  $year  연도
     * @param  int|null  $period  기간 번호
     * @return array
     */
    public function getDetail(?string $periodType = 'quarter', ?int $year = null, ?int $period = null): array
    {
        $tenantId = $this->tenantId();
        $now = Carbon::now();

        $year = $year ?? $now->year;
        $periodType = $periodType ?? 'quarter';
        $period = $period ?? $this->getCurrentPeriod($periodType, $now);

        [$startDate, $endDate] = $this->getPeriodDateRange($year, $periodType, $period);
        $periodLabel = $this->getPeriodLabel($year, $periodType, $period);

        $validStatuses = [TaxInvoice::STATUS_ISSUED, TaxInvoice::STATUS_SENT];

        // 매출 공급가액 + 세액
        $salesData = TaxInvoice::where('tenant_id', $tenantId)
            ->where('direction', TaxInvoice::DIRECTION_SALES)
            ->whereIn('status', $validStatuses)
            ->whereBetween('issue_date', [$startDate, $endDate])
            ->selectRaw('COALESCE(SUM(supply_amount), 0) as supply_amount, COALESCE(SUM(tax_amount), 0) as tax_amount')
            ->first();

        // 매입 공급가액 + 세액
        $purchasesData = TaxInvoice::where('tenant_id', $tenantId)
            ->where('direction', TaxInvoice::DIRECTION_PURCHASES)
            ->whereIn('status', $validStatuses)
            ->whereBetween('issue_date', [$startDate, $endDate])
            ->selectRaw('COALESCE(SUM(supply_amount), 0) as supply_amount, COALESCE(SUM(tax_amount), 0) as tax_amount')
            ->first();

        $salesSupplyAmount = (int) ($salesData->supply_amount ?? 0);
        $salesTaxAmount = (int) ($salesData->tax_amount ?? 0);
        $purchasesSupplyAmount = (int) ($purchasesData->supply_amount ?? 0);
        $purchasesTaxAmount = (int) ($purchasesData->tax_amount ?? 0);
        $estimatedPayment = $salesTaxAmount - $purchasesTaxAmount;

        // 신고기간 옵션 생성
        $periodOptions = $this->generatePeriodOptions($year, $periodType, $period);

        // 부가세 요약 테이블 (direction + invoice_type 별 GROUP BY)
        $referenceTable = TaxInvoice::where('tenant_id', $tenantId)
            ->whereIn('status', $validStatuses)
            ->whereBetween('issue_date', [$startDate, $endDate])
            ->selectRaw("
                direction,
                invoice_type,
                COALESCE(SUM(supply_amount), 0) as supply_amount,
                COALESCE(SUM(tax_amount), 0) as tax_amount
            ")
            ->groupBy('direction', 'invoice_type')
            ->get()
            ->map(fn ($row) => [
                'direction' => $row->direction,
                'direction_label' => $row->direction === TaxInvoice::DIRECTION_SALES ? '매출' : '매입',
                'invoice_type' => $row->invoice_type,
                'invoice_type_label' => match ($row->invoice_type) {
                    TaxInvoice::TYPE_TAX_INVOICE => '전자세금계산서',
                    TaxInvoice::TYPE_INVOICE => '계산서',
                    TaxInvoice::TYPE_MODIFIED_TAX_INVOICE => '수정세금계산서',
                    default => $row->invoice_type,
                },
                'supply_amount' => (int) $row->supply_amount,
                'tax_amount' => (int) $row->tax_amount,
            ])
            ->toArray();

        // 미발행/미수취 세금계산서 목록 (status=draft)
        $unissuedInvoices = TaxInvoice::where('tenant_id', $tenantId)
            ->where('status', TaxInvoice::STATUS_DRAFT)
            ->orderBy('issue_date', 'desc')
            ->limit(100)
            ->get()
            ->map(fn ($invoice) => [
                'id' => $invoice->id,
                'direction' => $invoice->direction,
                'direction_label' => $invoice->direction === TaxInvoice::DIRECTION_SALES ? '매출' : '매입',
                'issue_date' => $invoice->issue_date,
                'vendor_name' => $invoice->direction === TaxInvoice::DIRECTION_SALES
                    ? ($invoice->buyer_corp_name ?? '-')
                    : ($invoice->supplier_corp_name ?? '-'),
                'tax_amount' => (int) $invoice->tax_amount,
                'status' => $invoice->direction === TaxInvoice::DIRECTION_SALES ? '미발행' : '미수취',
            ])
            ->toArray();

        return [
            'period_label' => $periodLabel,
            'period_options' => $periodOptions,
            'summary' => [
                'sales_supply_amount' => $salesSupplyAmount,
                'sales_tax_amount' => $salesTaxAmount,
                'purchases_supply_amount' => $purchasesSupplyAmount,
                'purchases_tax_amount' => $purchasesTaxAmount,
                'estimated_payment' => (int) abs($estimatedPayment),
                'is_refund' => $estimatedPayment < 0,
            ],
            'reference_table' => $referenceTable,
            'unissued_invoices' => $unissuedInvoices,
        ];
    }

    /**
     * 신고기간 드롭다운 옵션 생성
     * 현재 기간 포함 최근 8개 기간
     */
    private function generatePeriodOptions(int $currentYear, string $periodType, int $currentPeriod): array
    {
        $options = [];
        $year = $currentYear;
        $period = $currentPeriod;

        for ($i = 0; $i < 8; $i++) {
            $label = $this->getPeriodLabel($year, $periodType, $period);
            $value = "{$year}-{$periodType}-{$period}";
            $options[] = ['value' => $value, 'label' => $label];

            // 이전 기간으로 이동
            $prev = $this->getPreviousPeriod($year, $periodType, $period);
            $year = $prev['year'];
            $period = $prev['period'];
        }

        return $options;
    }

    /**
     * 이전 기간 계산
     *
     * @return array{year: int, period: int}
     */
    private function getPreviousPeriod(int $year, string $periodType, int $period): array
    {
        return match ($periodType) {
            'quarter' => $period === 1
                ? ['year' => $year - 1, 'period' => 4]
                : ['year' => $year, 'period' => $period - 1],
            'half' => $period === 1
                ? ['year' => $year - 1, 'period' => 2]
                : ['year' => $year, 'period' => 1],
            'year' => ['year' => $year - 1, 'period' => 1],
            default => $period === 1
                ? ['year' => $year - 1, 'period' => 4]
                : ['year' => $year, 'period' => $period - 1],
        };
    }
}
