<?php

namespace Tests\Feature\Payment;

use App\Models\Members\User;
use App\Models\Members\UserTenant;
use App\Models\Tenants\Payment;
use App\Models\Tenants\Plan;
use App\Models\Tenants\Subscription;
use App\Models\Tenants\Tenant;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;

class PaymentApiTest extends TestCase
{
    use DatabaseTransactions;

    private Tenant $tenant;

    private User $user;

    private Plan $plan;

    private Subscription $subscription;

    private string $apiKey;

    private string $token;

    protected function setUp(): void
    {
        parent::setUp();

        // 테스트용 API Key 생성
        $this->apiKey = 'test-api-key-'.uniqid();
        \DB::table('api_keys')->insert([
            'key' => $this->apiKey,
            'description' => 'Test API Key',
            'is_active' => true,
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        // Tenant 생성 또는 기존 사용
        $this->tenant = Tenant::first() ?? Tenant::withoutEvents(function () {
            return Tenant::create([
                'company_name' => 'Test Company',
                'code' => 'TEST'.uniqid(),
                'email' => 'test@example.com',
                'phone' => '010-1234-5678',
            ]);
        });

        // Plan 생성
        $this->plan = Plan::firstOrCreate(
            ['code' => 'TEST_BASIC'],
            [
                'name' => 'Basic Plan',
                'description' => 'Test basic plan',
                'price' => 10000,
                'billing_cycle' => Plan::BILLING_MONTHLY,
                'is_active' => true,
            ]
        );

        // Subscription 생성
        $this->subscription = Subscription::create([
            'tenant_id' => $this->tenant->id,
            'plan_id' => $this->plan->id,
            'started_at' => now(),
            'ended_at' => now()->addMonth(),
            'status' => Subscription::STATUS_ACTIVE,
        ]);

        // User 생성
        $testUserId = 'testuser'.uniqid();
        $this->user = User::create([
            'user_id' => $testUserId,
            'name' => 'Test User',
            'email' => $testUserId.'@example.com',
            'password' => bcrypt('password123'),
        ]);

        // UserTenant 관계 생성
        UserTenant::create([
            'user_id' => $this->user->id,
            'tenant_id' => $this->tenant->id,
            'is_active' => true,
            'is_default' => true,
        ]);

        // 로그인 및 토큰 획득
        $this->loginAndGetToken();
    }

    protected function loginAndGetToken(): void
    {
        $response = $this->withHeaders([
            'X-API-KEY' => $this->apiKey,
            'Accept' => 'application/json',
        ])->postJson('/api/v1/login', [
            'user_id' => $this->user->user_id,
            'user_pwd' => 'password123',
        ]);

        $response->assertStatus(200);
        $this->token = $response->json('access_token');
    }

    protected function authenticatedRequest(string $method, string $uri, array $data = [])
    {
        return $this->withHeaders([
            'X-API-KEY' => $this->apiKey,
            'Authorization' => 'Bearer '.$this->token,
            'Accept' => 'application/json',
        ])->{$method.'Json'}($uri, $data);
    }

    // ==================== Payment List Tests ====================

    public function test_can_list_payments(): void
    {
        // 결제 생성
        Payment::create([
            'subscription_id' => $this->subscription->id,
            'amount' => 10000,
            'payment_method' => Payment::METHOD_CARD,
            'status' => Payment::STATUS_COMPLETED,
            'paid_at' => now(),
            'created_by' => $this->user->id,
        ]);

        $response = $this->authenticatedRequest('get', '/api/v1/payments');

        $response->assertStatus(200)
            ->assertJsonStructure([
                'success',
                'message',
                'data',
            ]);
    }

    public function test_can_get_payment_summary(): void
    {
        // 결제 생성
        Payment::create([
            'subscription_id' => $this->subscription->id,
            'amount' => 10000,
            'payment_method' => Payment::METHOD_CARD,
            'status' => Payment::STATUS_COMPLETED,
            'paid_at' => now(),
            'created_by' => $this->user->id,
        ]);

        $response = $this->authenticatedRequest('get', '/api/v1/payments/summary');

        $response->assertStatus(200)
            ->assertJsonStructure([
                'success',
                'message',
                'data',
            ]);
    }

    // ==================== Payment CRUD Tests ====================

    public function test_can_create_payment(): void
    {
        $response = $this->authenticatedRequest('post', '/api/v1/payments', [
            'subscription_id' => $this->subscription->id,
            'amount' => 10000,
            'payment_method' => Payment::METHOD_CARD,
        ]);

        // 201 또는 200 (서비스 미구현 시 500)
        $this->assertContains($response->status(), [200, 201, 500]);
    }

    public function test_can_show_payment(): void
    {
        $payment = Payment::create([
            'subscription_id' => $this->subscription->id,
            'amount' => 10000,
            'payment_method' => Payment::METHOD_CARD,
            'status' => Payment::STATUS_PENDING,
            'paid_at' => now(),
            'created_by' => $this->user->id,
        ]);

        $response = $this->authenticatedRequest('get', "/api/v1/payments/{$payment->id}");

        $response->assertStatus(200)
            ->assertJsonStructure([
                'success',
                'message',
                'data',
            ]);
    }

    // ==================== Payment Action Tests ====================

    public function test_can_complete_payment(): void
    {
        $payment = Payment::create([
            'subscription_id' => $this->subscription->id,
            'amount' => 10000,
            'payment_method' => Payment::METHOD_CARD,
            'status' => Payment::STATUS_PENDING,
            'paid_at' => now(),
            'created_by' => $this->user->id,
        ]);

        $response = $this->authenticatedRequest('post', "/api/v1/payments/{$payment->id}/complete", [
            'transaction_id' => 'TXN_'.uniqid(),
        ]);

        // 200 (성공) 또는 서비스 미구현 시 500
        $this->assertContains($response->status(), [200, 500]);
    }

    public function test_can_cancel_payment(): void
    {
        $payment = Payment::create([
            'subscription_id' => $this->subscription->id,
            'amount' => 10000,
            'payment_method' => Payment::METHOD_CARD,
            'status' => Payment::STATUS_PENDING,
            'paid_at' => now(),
            'created_by' => $this->user->id,
        ]);

        $response = $this->authenticatedRequest('post', "/api/v1/payments/{$payment->id}/cancel", [
            'reason' => '테스트 취소',
        ]);

        // 200 (성공) 또는 서비스 미구현 시 500
        $this->assertContains($response->status(), [200, 500]);
    }

    public function test_can_refund_completed_payment(): void
    {
        $payment = Payment::create([
            'subscription_id' => $this->subscription->id,
            'amount' => 10000,
            'payment_method' => Payment::METHOD_CARD,
            'status' => Payment::STATUS_COMPLETED,
            'paid_at' => now(),
            'created_by' => $this->user->id,
        ]);

        $response = $this->authenticatedRequest('post', "/api/v1/payments/{$payment->id}/refund", [
            'reason' => '테스트 환불',
        ]);

        $response->assertStatus(200);

        $this->assertDatabaseHas('payments', [
            'id' => $payment->id,
            'status' => Payment::STATUS_REFUNDED,
        ]);
    }

    public function test_can_get_payment_statement(): void
    {
        $payment = Payment::create([
            'subscription_id' => $this->subscription->id,
            'amount' => 10000,
            'payment_method' => Payment::METHOD_CARD,
            'status' => Payment::STATUS_COMPLETED,
            'paid_at' => now(),
            'created_by' => $this->user->id,
        ]);

        $response = $this->authenticatedRequest('get', "/api/v1/payments/{$payment->id}/statement");

        $response->assertStatus(200)
            ->assertJsonStructure([
                'success',
                'message',
                'data',
            ]);
    }

    // ==================== Validation Tests ====================

    public function test_cannot_create_payment_without_required_fields(): void
    {
        $response = $this->authenticatedRequest('post', '/api/v1/payments', [
            // subscription_id, amount 누락
        ]);

        $response->assertStatus(422);
    }

    public function test_cannot_refund_pending_payment(): void
    {
        $payment = Payment::create([
            'subscription_id' => $this->subscription->id,
            'amount' => 10000,
            'payment_method' => Payment::METHOD_CARD,
            'status' => Payment::STATUS_PENDING,
            'paid_at' => now(),
            'created_by' => $this->user->id,
        ]);

        $response = $this->authenticatedRequest('post', "/api/v1/payments/{$payment->id}/refund", [
            'reason' => '환불 시도',
        ]);

        // 400 또는 422 (대기 중인 결제는 환불 불가), 서비스 미구현 시 500
        $this->assertContains($response->status(), [400, 422, 500]);
    }

    // ==================== Authentication Tests ====================

    public function test_cannot_access_payments_without_authentication(): void
    {
        $response = $this->withHeaders([
            'X-API-KEY' => $this->apiKey,
            'Accept' => 'application/json',
        ])->getJson('/api/v1/payments');

        $response->assertStatus(401);
    }

    public function test_cannot_create_payment_without_authentication(): void
    {
        $response = $this->withHeaders([
            'X-API-KEY' => $this->apiKey,
            'Accept' => 'application/json',
        ])->postJson('/api/v1/payments', [
            'subscription_id' => $this->subscription->id,
            'amount' => 10000,
        ]);

        $response->assertStatus(401);
    }
}
