<?php

namespace App\Services;

use App\Models\ApiRequestLog;
use App\Models\Tenants\DataExport;
use App\Models\Tenants\Payment;
use App\Models\Tenants\Plan;
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;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class SubscriptionService extends Service
{
    // =========================================================================
    // 구독 목록/상세
    // =========================================================================

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

        $query = Subscription::query()
            ->where('tenant_id', $tenantId)
            ->with(['plan:id,name,code,price,billing_cycle']);

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

        // 유효한 구독만
        if (! empty($params['valid_only']) && $params['valid_only']) {
            $query->valid();
        }

        // 만료 예정 (N일 이내)
        if (! empty($params['expiring_within'])) {
            $query->expiringWithin((int) $params['expiring_within']);
        }

        // 날짜 범위 필터
        if (! empty($params['start_date'])) {
            $query->where('started_at', '>=', $params['start_date']);
        }
        if (! empty($params['end_date'])) {
            $query->where('started_at', '<=', $params['end_date']);
        }

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

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

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

    /**
     * 현재 활성 구독
     */
    public function current(): ?Subscription
    {
        $tenantId = $this->tenantId();

        return Subscription::query()
            ->where('tenant_id', $tenantId)
            ->valid()
            ->with(['plan', 'payments' => function ($q) {
                $q->completed()->orderBy('paid_at', 'desc')->limit(5);
            }])
            ->orderBy('started_at', 'desc')
            ->first();
    }

    /**
     * 구독 상세
     */
    public function show(int $id): Subscription
    {
        $tenantId = $this->tenantId();

        return Subscription::query()
            ->where('tenant_id', $tenantId)
            ->with([
                'plan',
                'payments' => function ($q) {
                    $q->orderBy('paid_at', 'desc');
                },
            ])
            ->findOrFail($id);
    }

    // =========================================================================
    // 구독 생성/취소
    // =========================================================================

    /**
     * 구독 생성 (결제 포함)
     */
    public function store(array $data): Subscription
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 요금제 확인
        $plan = Plan::active()->findOrFail($data['plan_id']);

        // 이미 활성 구독이 있는지 확인
        $existingSubscription = Subscription::query()
            ->where('tenant_id', $tenantId)
            ->valid()
            ->first();

        if ($existingSubscription) {
            throw new BadRequestHttpException(__('error.subscription.already_active'));
        }

        return DB::transaction(function () use ($data, $plan, $tenantId, $userId) {
            // 구독 생성
            $subscription = Subscription::create([
                'tenant_id' => $tenantId,
                'plan_id' => $plan->id,
                'started_at' => $data['started_at'] ?? now(),
                'status' => Subscription::STATUS_PENDING,
                'created_by' => $userId,
                'updated_by' => $userId,
            ]);

            // 결제 생성 (무료 요금제가 아닌 경우)
            if ($plan->price > 0) {
                $payment = Payment::create([
                    'subscription_id' => $subscription->id,
                    'amount' => $plan->price,
                    'payment_method' => $data['payment_method'] ?? Payment::METHOD_CARD,
                    'status' => Payment::STATUS_PENDING,
                    'created_by' => $userId,
                    'updated_by' => $userId,
                ]);

                // 결제 완료 처리 (실제 PG 연동 시 수정 필요)
                if (! empty($data['auto_complete']) && $data['auto_complete']) {
                    $payment->complete($data['transaction_id'] ?? null);

                    // 구독 활성화
                    $subscription->activate();
                }
            } else {
                // 무료 요금제는 바로 활성화
                Payment::create([
                    'subscription_id' => $subscription->id,
                    'amount' => 0,
                    'payment_method' => Payment::METHOD_FREE,
                    'status' => Payment::STATUS_COMPLETED,
                    'paid_at' => now(),
                    'created_by' => $userId,
                    'updated_by' => $userId,
                ]);

                $subscription->activate();
            }

            return $subscription->fresh(['plan', 'payments']);
        });
    }

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

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

        if (! $subscription->isCancellable()) {
            throw new BadRequestHttpException(__('error.subscription.not_cancellable'));
        }

        $subscription->cancel($reason);
        $subscription->updated_by = $userId;
        $subscription->save();

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

    /**
     * 구독 갱신
     */
    public function renew(int $id, array $data = []): Subscription
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

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

        if ($subscription->status !== Subscription::STATUS_ACTIVE) {
            throw new BadRequestHttpException(__('error.subscription.not_renewable'));
        }

        return DB::transaction(function () use ($subscription, $data, $userId) {
            $plan = $subscription->plan;

            // 결제 생성
            if ($plan->price > 0) {
                $payment = Payment::create([
                    'subscription_id' => $subscription->id,
                    'amount' => $plan->price,
                    'payment_method' => $data['payment_method'] ?? Payment::METHOD_CARD,
                    'status' => Payment::STATUS_PENDING,
                    'created_by' => $userId,
                    'updated_by' => $userId,
                ]);

                // 결제 완료 처리
                if (! empty($data['auto_complete']) && $data['auto_complete']) {
                    $payment->complete($data['transaction_id'] ?? null);
                    $subscription->renew();
                }
            } else {
                // 무료 갱신
                Payment::create([
                    'subscription_id' => $subscription->id,
                    'amount' => 0,
                    'payment_method' => Payment::METHOD_FREE,
                    'status' => Payment::STATUS_COMPLETED,
                    'paid_at' => now(),
                    'created_by' => $userId,
                    'updated_by' => $userId,
                ]);

                $subscription->renew();
            }

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

            return $subscription->fresh(['plan', 'payments']);
        });
    }

    // =========================================================================
    // 구독 상태 관리
    // =========================================================================

    /**
     * 구독 일시정지
     */
    public function suspend(int $id): Subscription
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

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

        if (! $subscription->suspend()) {
            throw new BadRequestHttpException(__('error.subscription.not_suspendable'));
        }

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

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

    /**
     * 구독 재개
     */
    public function resume(int $id): Subscription
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

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

        if (! $subscription->resume()) {
            throw new BadRequestHttpException(__('error.subscription.not_resumable'));
        }

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

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

    // =========================================================================
    // 사용량 조회
    // =========================================================================

    /**
     * 사용량 조회
     */
    public function usage(): array
    {
        $tenantId = $this->tenantId();

        $tenant = Tenant::with(['subscription.plan'])->findOrFail($tenantId);

        // 사용자 수
        $userCount = $tenant->users()->count();
        $maxUsers = $tenant->max_users ?? 0;

        // 저장공간
        $storageUsed = $tenant->storage_used ?? 0;
        $storageLimit = $tenant->storage_limit ?? 0;

        // API 호출 수 (일간 - 로그는 1일 보관)
        $apiCallsUsed = ApiRequestLog::where('tenant_id', $tenantId)
            ->whereDate('created_at', now()->toDateString())
            ->count();
        // 기본 일간 API 호출 제한 (10,000회)
        $apiCallsLimit = 10000;

        // 구독 정보
        $subscription = $tenant->subscription;
        $remainingDays = null;
        $planName = null;

        if ($subscription && $subscription->is_valid) {
            $remainingDays = $subscription->remaining_days;
            $planName = $subscription->plan?->name;
        }

        return [
            'users' => [
                'used' => $userCount,
                'limit' => $maxUsers,
                'percentage' => $maxUsers > 0 ? round(($userCount / $maxUsers) * 100, 1) : 0,
            ],
            'storage' => [
                'used' => $storageUsed,
                'used_formatted' => $tenant->getStorageUsedFormatted(),
                'limit' => $storageLimit,
                'limit_formatted' => $tenant->getStorageLimitFormatted(),
                'percentage' => $storageLimit > 0 ? round(($storageUsed / $storageLimit) * 100, 1) : 0,
            ],
            'api_calls' => [
                'used' => $apiCallsUsed,
                'limit' => $apiCallsLimit,
                'percentage' => $apiCallsLimit > 0 ? round(($apiCallsUsed / $apiCallsLimit) * 100, 1) : 0,
            ],
            'subscription' => [
                'plan' => $planName,
                'status' => $subscription?->status,
                'remaining_days' => $remainingDays,
                'started_at' => $subscription?->started_at?->toDateString(),
                'ended_at' => $subscription?->ended_at?->toDateString(),
            ],
        ];
    }

    // =========================================================================
    // 데이터 내보내기
    // =========================================================================

    /**
     * 내보내기 요청 생성
     */
    public function createExport(array $data): DataExport
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        // 진행 중인 내보내기가 있는지 확인
        $pendingExport = DataExport::where('tenant_id', $tenantId)
            ->whereIn('status', [DataExport::STATUS_PENDING, DataExport::STATUS_PROCESSING])
            ->first();

        if ($pendingExport) {
            throw new BadRequestHttpException(__('error.export.already_in_progress'));
        }

        $export = DataExport::create([
            'tenant_id' => $tenantId,
            'export_type' => $data['export_type'] ?? DataExport::TYPE_ALL,
            'status' => DataExport::STATUS_PENDING,
            'options' => $data['options'] ?? null,
            'created_by' => $userId,
        ]);

        // TODO: 비동기 Job 디스패치
        // dispatch(new ProcessDataExport($export));

        return $export;
    }

    /**
     * 내보내기 상태 조회
     */
    public function getExport(int $id): DataExport
    {
        $tenantId = $this->tenantId();

        $export = DataExport::where('tenant_id', $tenantId)->find($id);

        if (! $export) {
            throw new NotFoundHttpException(__('error.export.not_found'));
        }

        return $export;
    }

    /**
     * 내보내기 목록 조회
     */
    public function getExports(array $params = []): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        $query = DataExport::where('tenant_id', $tenantId)
            ->with('creator:id,name,email');

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

        // 유형 필터
        if (! empty($params['export_type'])) {
            $query->where('export_type', $params['export_type']);
        }

        $query->orderBy('created_at', 'desc');

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

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