<?php

namespace App\Services;

use App\Models\Tenants\Payment;
use App\Models\Tenants\Subscription;
use App\Models\Tenants\Tenant;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

class PaymentService extends Service
{
    // =========================================================================
    // 결제 목록/상세
    // =========================================================================

    /**
     * 결제 목록
     */
    public function index(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        // 테넌트의 구독에 속한 결제만 조회
        $subscriptionIds = Subscription::query()
            ->where('tenant_id', $tenantId)
            ->pluck('id');

        $query = Payment::query()
            ->whereIn('subscription_id', $subscriptionIds)
            ->with(['subscription.plan:id,name,code']);

        // 상태 필터
        if (! empty($params['status'])) {
            $query->ofStatus($params['status']);
        }

        // 결제 수단 필터
        if (! empty($params['payment_method'])) {
            $query->ofMethod($params['payment_method']);
        }

        // 날짜 범위 필터
        $query->betweenDates(
            $params['start_date'] ?? null,
            $params['end_date'] ?? null
        );

        // 검색 (거래 ID, 메모)
        if (! empty($params['search'])) {
            $search = $params['search'];
            $query->where(function ($q) use ($search) {
                $q->where('transaction_id', 'like', "%{$search}%")
                    ->orWhere('memo', 'like', "%{$search}%");
            });
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'created_at';
        $sortDir = $params['sort_dir'] ?? 'desc';
        $query->orderBy($sortBy, $sortDir);

        $perPage = $params['per_page'] ?? 20;

        return $query->paginate($perPage);
    }

    /**
     * 결제 상세
     */
    public function show(int $id): Payment
    {
        $tenantId = $this->tenantId();

        // 테넌트 검증을 위해 구독 통해 조회
        $subscriptionIds = Subscription::query()
            ->where('tenant_id', $tenantId)
            ->pluck('id');

        return Payment::query()
            ->whereIn('subscription_id', $subscriptionIds)
            ->with(['subscription.plan'])
            ->findOrFail($id);
    }

    /**
     * 결제 요약 통계
     */
    public function summary(array $params = []): array
    {
        $tenantId = $this->tenantId();

        $subscriptionIds = Subscription::query()
            ->where('tenant_id', $tenantId)
            ->pluck('id');

        $query = Payment::query()
            ->whereIn('subscription_id', $subscriptionIds);

        // 날짜 범위 필터
        if (! empty($params['start_date']) || ! empty($params['end_date'])) {
            $query->betweenDates(
                $params['start_date'] ?? null,
                $params['end_date'] ?? null
            );
        }

        $stats = $query->selectRaw('
            COUNT(*) as total_count,
            SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as completed_count,
            SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as pending_count,
            SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as failed_count,
            SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as cancelled_count,
            SUM(CASE WHEN status = ? THEN 1 ELSE 0 END) as refunded_count,
            SUM(CASE WHEN status = ? THEN amount ELSE 0 END) as total_completed_amount,
            SUM(CASE WHEN status = ? THEN amount ELSE 0 END) as total_refunded_amount
        ', [
            Payment::STATUS_COMPLETED,
            Payment::STATUS_PENDING,
            Payment::STATUS_FAILED,
            Payment::STATUS_CANCELLED,
            Payment::STATUS_REFUNDED,
            Payment::STATUS_COMPLETED,
            Payment::STATUS_REFUNDED,
        ])->first();

        // 결제 수단별 집계
        $byMethod = Payment::query()
            ->whereIn('subscription_id', $subscriptionIds)
            ->completed()
            ->selectRaw('payment_method, COUNT(*) as count, SUM(amount) as total_amount')
            ->groupBy('payment_method')
            ->get()
            ->keyBy('payment_method')
            ->map(fn ($item) => [
                'count' => (int) $item->count,
                'total_amount' => (float) $item->total_amount,
            ])
            ->toArray();

        return [
            'total_count' => (int) $stats->total_count,
            'completed_count' => (int) $stats->completed_count,
            'pending_count' => (int) $stats->pending_count,
            'failed_count' => (int) $stats->failed_count,
            'cancelled_count' => (int) $stats->cancelled_count,
            'refunded_count' => (int) $stats->refunded_count,
            'total_completed_amount' => (float) $stats->total_completed_amount,
            'total_refunded_amount' => (float) $stats->total_refunded_amount,
            'net_amount' => (float) ($stats->total_completed_amount - $stats->total_refunded_amount),
            'by_method' => $byMethod,
        ];
    }

    // =========================================================================
    // 결제 처리
    // =========================================================================

    /**
     * 결제 생성 (수동)
     */
    public function store(array $data): Payment
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 구독 확인
        $subscription = Subscription::query()
            ->where('tenant_id', $tenantId)
            ->findOrFail($data['subscription_id']);

        return DB::transaction(function () use ($data, $subscription, $userId) {
            $payment = Payment::create([
                'subscription_id' => $subscription->id,
                'amount' => $data['amount'],
                'payment_method' => $data['payment_method'] ?? Payment::METHOD_CARD,
                'transaction_id' => $data['transaction_id'] ?? null,
                'status' => Payment::STATUS_PENDING,
                'memo' => $data['memo'] ?? null,
                'created_by' => $userId,
                'updated_by' => $userId,
            ]);

            // 자동 완료 처리
            if (! empty($data['auto_complete']) && $data['auto_complete']) {
                $payment->complete($data['transaction_id'] ?? null);
            }

            return $payment->fresh(['subscription.plan']);
        });
    }

    /**
     * 결제 완료 처리
     */
    public function complete(int $id, ?string $transactionId = null): Payment
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $subscriptionIds = Subscription::query()
            ->where('tenant_id', $tenantId)
            ->pluck('id');

        $payment = Payment::query()
            ->whereIn('subscription_id', $subscriptionIds)
            ->findOrFail($id);

        if (! $payment->complete($transactionId)) {
            throw new BadRequestHttpException(__('error.payment.not_completable'));
        }

        $payment->updated_by = $userId;
        $payment->save();

        // 구독이 대기 중이면 활성화
        $subscription = $payment->subscription;
        if ($subscription->status === Subscription::STATUS_PENDING) {
            $subscription->activate();
        }

        return $payment->fresh(['subscription.plan']);
    }

    /**
     * 결제 취소
     */
    public function cancel(int $id, ?string $reason = null): Payment
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $subscriptionIds = Subscription::query()
            ->where('tenant_id', $tenantId)
            ->pluck('id');

        $payment = Payment::query()
            ->whereIn('subscription_id', $subscriptionIds)
            ->findOrFail($id);

        if (! $payment->cancel($reason)) {
            throw new BadRequestHttpException(__('error.payment.not_cancellable'));
        }

        $payment->updated_by = $userId;
        $payment->save();

        return $payment->fresh(['subscription.plan']);
    }

    /**
     * 환불 처리
     */
    public function refund(int $id, ?string $reason = null): Payment
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        $subscriptionIds = Subscription::query()
            ->where('tenant_id', $tenantId)
            ->pluck('id');

        $payment = Payment::query()
            ->whereIn('subscription_id', $subscriptionIds)
            ->findOrFail($id);

        if (! $payment->refund($reason)) {
            throw new BadRequestHttpException(__('error.payment.not_refundable'));
        }

        $payment->updated_by = $userId;
        $payment->save();

        return $payment->fresh(['subscription.plan']);
    }

    // =========================================================================
    // 결제 명세서
    // =========================================================================

    /**
     * 결제 명세서 조회
     */
    public function statement(int $id): array
    {
        $tenantId = $this->tenantId();

        // 테넌트 검증 및 결제 조회
        $subscriptionIds = Subscription::query()
            ->where('tenant_id', $tenantId)
            ->pluck('id');

        $payment = Payment::query()
            ->whereIn('subscription_id', $subscriptionIds)
            ->with(['subscription.plan'])
            ->findOrFail($id);

        // 테넌트 정보 조회
        $tenant = Tenant::findOrFail($tenantId);

        $subscription = $payment->subscription;
        $plan = $subscription->plan;

        return [
            'statement_no' => sprintf('INV-%s-%06d', $payment->paid_at?->format('Ymd') ?? now()->format('Ymd'), $payment->id),
            'issued_at' => now()->toIso8601String(),
            'payment' => [
                'id' => $payment->id,
                'amount' => $payment->amount,
                'formatted_amount' => $payment->formatted_amount,
                'payment_method' => $payment->payment_method,
                'payment_method_label' => $payment->payment_method_label,
                'transaction_id' => $payment->transaction_id,
                'status' => $payment->status,
                'status_label' => $payment->status_label,
                'paid_at' => $payment->paid_at?->toIso8601String(),
                'memo' => $payment->memo,
            ],
            'subscription' => [
                'id' => $subscription->id,
                'started_at' => $subscription->started_at?->toDateString(),
                'ended_at' => $subscription->ended_at?->toDateString(),
                'status' => $subscription->status,
                'status_label' => $subscription->status_label,
            ],
            'plan' => $plan ? [
                'id' => $plan->id,
                'name' => $plan->name,
                'code' => $plan->code,
                'price' => $plan->price,
                'billing_cycle' => $plan->billing_cycle,
                'billing_cycle_label' => $plan->billing_cycle_label ?? $plan->billing_cycle,
            ] : null,
            'customer' => [
                'tenant_id' => $tenant->id,
                'company_name' => $tenant->company_name,
                'business_number' => $tenant->business_number ?? null,
                'representative' => $tenant->representative ?? null,
                'address' => $tenant->address ?? null,
                'email' => $tenant->email ?? null,
                'phone' => $tenant->phone ?? null,
            ],
            'items' => [
                [
                    'description' => $plan ? sprintf('%s 구독 (%s)', $plan->name, $subscription->started_at?->format('Y.m.d') ?? '-') : '구독 서비스',
                    'quantity' => 1,
                    'unit_price' => $payment->amount,
                    'amount' => $payment->amount,
                ],
            ],
            'subtotal' => $payment->amount,
            'tax' => 0, // VAT 별도 시 계산 필요
            'total' => $payment->amount,
        ];
    }
}
