<?php

namespace App\Services\Barobill;

use App\Models\Barobill\BarobillBillingRecord;
use App\Models\Barobill\BarobillMonthlySummary;
use App\Models\Barobill\BarobillSubscription;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;

/**
 * 바로빌 과금 서비스
 *
 * 월정액 구독 관리 및 과금 처리
 */
class BarobillBillingService
{
    /**
     * 회원사의 구독 목록 조회
     */
    public function getSubscriptions(int $memberId): array
    {
        return BarobillSubscription::where('member_id', $memberId)
            ->orderBy('service_type')
            ->get()
            ->toArray();
    }

    /**
     * 구독 등록/수정
     */
    public function saveSubscription(int $memberId, string $serviceType, array $data): BarobillSubscription
    {
        return BarobillSubscription::updateOrCreate(
            [
                'member_id' => $memberId,
                'service_type' => $serviceType,
            ],
            [
                'monthly_fee' => $data['monthly_fee'] ?? BarobillSubscription::DEFAULT_MONTHLY_FEES[$serviceType] ?? 0,
                'started_at' => $data['started_at'] ?? now()->toDateString(),
                'ended_at' => $data['ended_at'] ?? null,
                'is_active' => $data['is_active'] ?? true,
                'memo' => $data['memo'] ?? null,
            ]
        );
    }

    /**
     * 구독 해지
     */
    public function cancelSubscription(int $subscriptionId): bool
    {
        $subscription = BarobillSubscription::find($subscriptionId);
        if (! $subscription) {
            return false;
        }

        $subscription->update([
            'ended_at' => now()->toDateString(),
            'is_active' => false,
        ]);

        return true;
    }

    /**
     * 월별 과금 처리 (배치용)
     *
     * 매월 1일에 실행하여 전월 구독료 과금
     */
    public function processMonthlyBilling(?string $billingMonth = null): array
    {
        $billingMonth = $billingMonth ?? now()->format('Y-m');
        $billedAt = Carbon::parse($billingMonth.'-01');

        $results = [
            'billing_month' => $billingMonth,
            'processed' => 0,
            'skipped' => 0,
            'errors' => [],
        ];

        // 활성 구독 조회
        $subscriptions = BarobillSubscription::active()
            ->with('member')
            ->get();

        foreach ($subscriptions as $subscription) {
            try {
                // 이미 과금된 기록이 있는지 확인
                $exists = BarobillBillingRecord::where('member_id', $subscription->member_id)
                    ->where('billing_month', $billingMonth)
                    ->where('service_type', $subscription->service_type)
                    ->where('billing_type', 'subscription')
                    ->exists();

                if ($exists) {
                    $results['skipped']++;

                    continue;
                }

                // 과금 기록 생성
                BarobillBillingRecord::create([
                    'member_id' => $subscription->member_id,
                    'billing_month' => $billingMonth,
                    'service_type' => $subscription->service_type,
                    'billing_type' => 'subscription',
                    'quantity' => 1,
                    'unit_price' => $subscription->monthly_fee,
                    'total_amount' => $subscription->monthly_fee,
                    'billed_at' => $billedAt,
                    'description' => BarobillSubscription::SERVICE_TYPES[$subscription->service_type].' 월정액',
                ]);

                $results['processed']++;

            } catch (\Exception $e) {
                $results['errors'][] = [
                    'member_id' => $subscription->member_id,
                    'service_type' => $subscription->service_type,
                    'error' => $e->getMessage(),
                ];
                Log::error('월정액 과금 처리 실패', [
                    'subscription_id' => $subscription->id,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        // 월별 집계 갱신
        $this->updateMonthlySummaries($billingMonth);

        return $results;
    }

    /**
     * 건별 사용량 과금 (세금계산서)
     */
    public function recordUsage(int $memberId, string $serviceType, int $quantity, ?string $billingMonth = null): BarobillBillingRecord
    {
        $billingMonth = $billingMonth ?? now()->format('Y-m');
        $unitPrice = BarobillBillingRecord::USAGE_UNIT_PRICES[$serviceType] ?? 0;

        $record = BarobillBillingRecord::updateOrCreate(
            [
                'member_id' => $memberId,
                'billing_month' => $billingMonth,
                'service_type' => $serviceType,
                'billing_type' => 'usage',
            ],
            [
                'quantity' => $quantity,
                'unit_price' => $unitPrice,
                'total_amount' => $quantity * $unitPrice,
                'billed_at' => now()->toDateString(),
                'description' => BarobillBillingRecord::SERVICE_TYPES[$serviceType].' '.$quantity.'건',
            ]
        );

        // 집계 갱신
        BarobillMonthlySummary::updateOrCreateSummary($memberId, $billingMonth);

        return $record;
    }

    /**
     * 월별 집계 갱신
     */
    public function updateMonthlySummaries(string $billingMonth): void
    {
        // 해당 월에 과금 기록이 있는 회원사 조회
        $memberIds = BarobillBillingRecord::where('billing_month', $billingMonth)
            ->distinct()
            ->pluck('member_id');

        foreach ($memberIds as $memberId) {
            BarobillMonthlySummary::updateOrCreateSummary($memberId, $billingMonth);
        }
    }

    /**
     * 월별 과금 현황 조회
     */
    public function getMonthlyBillingList(string $billingMonth, ?int $tenantId = null): array
    {
        $query = BarobillMonthlySummary::with(['member.tenant'])
            ->where('billing_month', $billingMonth);

        if ($tenantId) {
            $query->whereHas('member', function ($q) use ($tenantId) {
                $q->where('tenant_id', $tenantId);
            });
        }

        return $query->orderBy('grand_total', 'desc')->get()->toArray();
    }

    /**
     * 월별 합계 조회
     */
    public function getMonthlyTotal(string $billingMonth, ?int $tenantId = null): array
    {
        $query = BarobillMonthlySummary::where('billing_month', $billingMonth);

        if ($tenantId) {
            $query->whereHas('member', function ($q) use ($tenantId) {
                $q->where('tenant_id', $tenantId);
            });
        }

        $result = $query->selectRaw('
            COUNT(*) as member_count,
            SUM(bank_account_fee) as bank_account_fee,
            SUM(card_fee) as card_fee,
            SUM(hometax_fee) as hometax_fee,
            SUM(subscription_total) as subscription_total,
            SUM(tax_invoice_count) as tax_invoice_count,
            SUM(tax_invoice_amount) as tax_invoice_amount,
            SUM(usage_total) as usage_total,
            SUM(grand_total) as grand_total
        ')->first();

        return [
            'billing_month' => $billingMonth,
            'member_count' => (int) ($result->member_count ?? 0),
            'bank_account_fee' => (int) ($result->bank_account_fee ?? 0),
            'card_fee' => (int) ($result->card_fee ?? 0),
            'hometax_fee' => (int) ($result->hometax_fee ?? 0),
            'subscription_total' => (int) ($result->subscription_total ?? 0),
            'tax_invoice_count' => (int) ($result->tax_invoice_count ?? 0),
            'tax_invoice_amount' => (int) ($result->tax_invoice_amount ?? 0),
            'usage_total' => (int) ($result->usage_total ?? 0),
            'grand_total' => (int) ($result->grand_total ?? 0),
        ];
    }

    /**
     * 연간 과금 추이 조회
     */
    public function getYearlyTrend(int $year, ?int $tenantId = null): array
    {
        $months = [];
        for ($m = 1; $m <= 12; $m++) {
            $billingMonth = sprintf('%d-%02d', $year, $m);
            $months[$billingMonth] = $this->getMonthlyTotal($billingMonth, $tenantId);
        }

        return $months;
    }
}
