<?php

namespace App\Http\Controllers\Finance;

use App\Http\Controllers\Controller;
use App\Models\Barobill\CardTransaction;
use App\Models\Barobill\CardTransactionHide;
use App\Models\Finance\CorporateCard;
use App\Models\Finance\CorporateCardPrepayment;
use App\Models\System\Holiday;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class CorporateCardController extends Controller
{
    /**
     * 카드 목록 조회
     */
    public function index(Request $request): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);

        $cards = CorporateCard::forTenant($tenantId)
            ->orderBy('created_at', 'desc')
            ->get()
            ->map(function ($card) {
                return [
                    'id' => $card->id,
                    'cardName' => $card->card_name,
                    'cardCompany' => $card->card_company,
                    'cardNumber' => $card->card_number,
                    'cardType' => $card->card_type,
                    'paymentDay' => $card->payment_day,
                    'creditLimit' => (float) $card->credit_limit,
                    'currentUsage' => (float) $card->current_usage,
                    'cardHolderName' => $card->card_holder_name,
                    'actualUser' => $card->actual_user,
                    'expiryDate' => $card->expiry_date,
                    'cvc' => $card->cvc,
                    'status' => $card->status,
                    'memo' => $card->memo,
                ];
            });

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

    /**
     * 카드 등록
     */
    public function store(Request $request): JsonResponse
    {
        $request->validate([
            'cardName' => 'required|string|max:100',
            'cardCompany' => 'required|string|max:50',
            'cardNumber' => 'required|string|max:30',
            'cardType' => 'required|in:credit,debit',
            'cardHolderName' => 'required|string|max:100',
            'actualUser' => 'required|string|max:100',
        ]);

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

        $card = CorporateCard::create([
            'tenant_id' => $tenantId,
            'card_name' => $request->input('cardName'),
            'card_company' => $request->input('cardCompany'),
            'card_number' => $request->input('cardNumber'),
            'card_type' => $request->input('cardType'),
            'payment_day' => $request->input('paymentDay', 15),
            'credit_limit' => $request->input('creditLimit', 0),
            'current_usage' => 0,
            'card_holder_name' => $request->input('cardHolderName'),
            'actual_user' => $request->input('actualUser'),
            'expiry_date' => $request->input('expiryDate'),
            'cvc' => $request->input('cvc'),
            'status' => $request->input('status', 'active'),
            'memo' => $request->input('memo'),
        ]);

        return response()->json([
            'success' => true,
            'message' => '카드가 등록되었습니다.',
            'data' => [
                'id' => $card->id,
                'cardName' => $card->card_name,
                'cardCompany' => $card->card_company,
                'cardNumber' => $card->card_number,
                'cardType' => $card->card_type,
                'paymentDay' => $card->payment_day,
                'creditLimit' => (float) $card->credit_limit,
                'currentUsage' => (float) $card->current_usage,
                'cardHolderName' => $card->card_holder_name,
                'actualUser' => $card->actual_user,
                'expiryDate' => $card->expiry_date,
                'cvc' => $card->cvc,
                'status' => $card->status,
                'memo' => $card->memo,
            ],
        ]);
    }

    /**
     * 카드 수정
     */
    public function update(Request $request, int $id): JsonResponse
    {
        $card = CorporateCard::findOrFail($id);

        $request->validate([
            'cardName' => 'required|string|max:100',
            'cardCompany' => 'required|string|max:50',
            'cardNumber' => 'required|string|max:30',
            'cardType' => 'required|in:credit,debit',
            'cardHolderName' => 'required|string|max:100',
            'actualUser' => 'required|string|max:100',
        ]);

        $card->update([
            'card_name' => $request->input('cardName'),
            'card_company' => $request->input('cardCompany'),
            'card_number' => $request->input('cardNumber'),
            'card_type' => $request->input('cardType'),
            'payment_day' => $request->input('paymentDay', 15),
            'credit_limit' => $request->input('creditLimit', 0),
            'card_holder_name' => $request->input('cardHolderName'),
            'actual_user' => $request->input('actualUser'),
            'expiry_date' => $request->input('expiryDate'),
            'cvc' => $request->input('cvc'),
            'status' => $request->input('status', 'active'),
            'memo' => $request->input('memo'),
        ]);

        return response()->json([
            'success' => true,
            'message' => '카드가 수정되었습니다.',
            'data' => [
                'id' => $card->id,
                'cardName' => $card->card_name,
                'cardCompany' => $card->card_company,
                'cardNumber' => $card->card_number,
                'cardType' => $card->card_type,
                'paymentDay' => $card->payment_day,
                'creditLimit' => (float) $card->credit_limit,
                'currentUsage' => (float) $card->current_usage,
                'cardHolderName' => $card->card_holder_name,
                'actualUser' => $card->actual_user,
                'expiryDate' => $card->expiry_date,
                'cvc' => $card->cvc,
                'status' => $card->status,
                'memo' => $card->memo,
            ],
        ]);
    }

    /**
     * 카드 비활성화
     */
    public function deactivate(int $id): JsonResponse
    {
        $card = CorporateCard::findOrFail($id);
        $card->update(['status' => 'inactive']);

        return response()->json([
            'success' => true,
            'message' => '카드가 비활성화되었습니다.',
        ]);
    }

    /**
     * 카드 영구삭제
     */
    public function destroy(int $id): JsonResponse
    {
        $card = CorporateCard::findOrFail($id);
        $card->forceDelete();

        return response()->json([
            'success' => true,
            'message' => '카드가 영구 삭제되었습니다.',
        ]);
    }

    /**
     * 요약 데이터 (결제일, 사용금액, 선불결제)
     */
    public function summary(): JsonResponse
    {
        $tenantId = session('selected_tenant_id', 1);
        $now = Carbon::now();

        // 활성 카드 조회
        $activeCards = CorporateCard::forTenant($tenantId)->active()->get();

        if ($activeCards->isEmpty()) {
            return response()->json([
                'success' => true,
                'data' => [
                    'paymentDate' => null,
                    'paymentDay' => 15,
                    'originalDate' => null,
                    'isAdjusted' => false,
                    'billingPeriod' => null,
                    'billingUsage' => 0,
                    'prepaidAmount' => 0,
                    'prepaidMemo' => '',
                ],
            ]);
        }

        // 대표 결제일 (첫 번째 활성 신용카드 기준)
        $creditCard = $activeCards->firstWhere('card_type', 'credit');
        $paymentDay = $creditCard ? $creditCard->payment_day : 15;

        // 휴일 조정 결제일 계산 (현재 월)
        $originalDate = $this->createPaymentDate($now->year, $now->month, $paymentDay);
        $adjustedDate = $this->getAdjustedPaymentDate($tenantId, $now->year, $now->month, $paymentDay);

        // 현재일이 결제일을 지났으면 다음 월로 이동
        if ($now->greaterThan($adjustedDate)) {
            $nextMonth = $now->copy()->addMonth();
            $originalDate = $this->createPaymentDate($nextMonth->year, $nextMonth->month, $paymentDay);
            $adjustedDate = $this->getAdjustedPaymentDate($tenantId, $nextMonth->year, $nextMonth->month, $paymentDay);
        }

        $isAdjusted = ! $originalDate->isSameDay($adjustedDate);

        // 청구기간: 결제일 기준 전월 1일 ~ 결제일
        $billingStart = $adjustedDate->copy()->subMonth()->startOfMonth();
        $billingEnd = $adjustedDate->copy();

        // 카드번호 목록
        $cardNumbers = $activeCards->pluck('card_number')->toArray();

        // 사용금액 계산 (전체 + 카드별)
        $usageResult = $this->calculateBillingUsage(
            $tenantId,
            $billingStart->format('Y-m-d'),
            $billingEnd->format('Y-m-d'),
            $cardNumbers
        );

        // 선불결제 금액 (결제일 기준 월)
        $yearMonth = $adjustedDate->format('Y-m');
        $prepayment = CorporateCardPrepayment::getOrCreate($tenantId, $yearMonth);

        return response()->json([
            'success' => true,
            'data' => [
                'paymentDate' => $adjustedDate->format('Y-m-d'),
                'paymentDay' => $paymentDay,
                'originalDate' => $originalDate->format('Y-m-d'),
                'isAdjusted' => $isAdjusted,
                'billingPeriod' => [
                    'start' => $billingStart->format('Y-m-d'),
                    'end' => $billingEnd->format('Y-m-d'),
                ],
                'billingUsage' => $usageResult['total'],
                'cardUsages' => $usageResult['perCard'],
                'prepaidAmount' => (int) $prepayment->amount,
                'prepaidMemo' => $prepayment->memo ?? '',
                'prepaidItems' => $prepayment->items ?? [],
            ],
        ]);
    }

    /**
     * 결제 내역 수정
     */
    public function updatePrepayment(Request $request): JsonResponse
    {
        $request->validate([
            'items' => 'present|array',
            'items.*.date' => 'required|date',
            'items.*.amount' => 'required|integer|min:0',
            'items.*.description' => 'nullable|string|max:200',
        ]);

        $tenantId = session('selected_tenant_id', 1);
        $yearMonth = $this->getBillingYearMonth($tenantId);

        $items = collect($request->input('items', []))->filter(fn ($item) => ($item['amount'] ?? 0) > 0)->values()->toArray();
        $amount = collect($items)->sum('amount');

        $prepayment = CorporateCardPrepayment::updateOrCreate(
            ['tenant_id' => $tenantId, 'year_month' => $yearMonth],
            ['amount' => $amount, 'items' => $items, 'memo' => null]
        );

        return response()->json([
            'success' => true,
            'message' => '결제 내역이 저장되었습니다.',
            'data' => [
                'amount' => (int) $prepayment->amount,
                'items' => $prepayment->items ?? [],
            ],
        ]);
    }

    /**
     * 청구 기준 year_month 계산 (summary와 동일한 로직)
     */
    private function getBillingYearMonth(int $tenantId): string
    {
        $now = Carbon::now();

        $activeCards = CorporateCard::forTenant($tenantId)->active()->get();
        $creditCard = $activeCards->firstWhere('card_type', 'credit');
        $paymentDay = $creditCard ? $creditCard->payment_day : 15;

        $adjustedDate = $this->getAdjustedPaymentDate($tenantId, $now->year, $now->month, $paymentDay);

        if ($now->greaterThan($adjustedDate)) {
            $nextMonth = $now->copy()->addMonth();
            $adjustedDate = $this->getAdjustedPaymentDate($tenantId, $nextMonth->year, $nextMonth->month, $paymentDay);
        }

        return $adjustedDate->format('Y-m');
    }

    /**
     * 결제일 날짜 생성 (월 말일 초과 방지)
     */
    private function createPaymentDate(int $year, int $month, int $day): Carbon
    {
        $maxDay = Carbon::create($year, $month)->daysInMonth;

        return Carbon::create($year, $month, min($day, $maxDay));
    }

    /**
     * 휴일/주말 조정된 결제일 계산
     */
    private function getAdjustedPaymentDate(int $tenantId, int $year, int $month, int $paymentDay): Carbon
    {
        $date = $this->createPaymentDate($year, $month, $paymentDay);

        // 해당 기간의 휴일 조회
        $holidays = Holiday::forTenant($tenantId)
            ->where('start_date', '<=', $date->copy()->addDays(10)->format('Y-m-d'))
            ->where('end_date', '>=', $date->format('Y-m-d'))
            ->get();

        $holidayDates = [];
        foreach ($holidays as $h) {
            $current = $h->start_date->copy();
            while ($current <= $h->end_date) {
                $holidayDates[] = $current->format('Y-m-d');
                $current->addDay();
            }
        }

        // 토/일/공휴일이면 다음 영업일로 이동
        while ($date->isWeekend() || in_array($date->format('Y-m-d'), $holidayDates)) {
            $date->addDay();
        }

        return $date;
    }

    /**
     * 청구기간 사용금액 계산 (바로빌 카드거래 합산)
     */
    private function calculateBillingUsage(int $tenantId, string $startDate, string $endDate, array $cardNumbers): array
    {
        // 카드번호 정규화 (하이픈 제거) + 원본↔정규화 매핑
        $normalizedNums = array_map(fn ($num) => str_replace('-', '', $num), $cardNumbers);

        if (empty($normalizedNums)) {
            return ['total' => 0, 'perCard' => []];
        }

        // use_date는 YYYYMMDD 형식
        $startYmd = str_replace('-', '', $startDate);
        $endYmd = str_replace('-', '', $endDate);

        // 숨긴 거래 키 조회
        $hiddenKeys = CardTransactionHide::getHiddenKeys($tenantId, $startYmd, $endYmd);

        // 바로빌 카드거래 조회
        $transactions = CardTransaction::where('tenant_id', $tenantId)
            ->whereIn('card_num', $normalizedNums)
            ->whereBetween('use_date', [$startYmd, $endYmd])
            ->get();

        $total = 0;
        $perCard = [];
        foreach ($transactions as $tx) {
            if ($hiddenKeys->contains($tx->unique_key)) {
                continue;
            }

            $amount = 0;
            if ($tx->approval_type === '1') {
                $amount = (int) $tx->approval_amount;
            } elseif ($tx->approval_type === '2') {
                $amount = -(int) $tx->approval_amount;
            }

            $total += $amount;
            $cardNum = $tx->card_num;
            $perCard[$cardNum] = ($perCard[$cardNum] ?? 0) + $amount;
        }

        return ['total' => $total, 'perCard' => (object) $perCard];
    }
}
