<?php

namespace Tests\Feature\User;

use App\Models\Members\User;
use App\Models\Members\UserTenant;
use App\Models\Permissions\Role;
use App\Models\Tenants\Tenant;
use App\Models\UserInvitation;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;

class UserInvitationApiTest extends TestCase
{
    use DatabaseTransactions;

    private Tenant $tenant;

    private User $user;

    private Role $role;

    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',
            ]);
        });

        // Role 생성
        $this->role = Role::firstOrCreate(
            ['tenant_id' => $this->tenant->id, 'name' => 'Member'],
            ['description' => 'Test member role']
        );

        // 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);
    }

    // ==================== Invitation List Tests ====================

    public function test_can_list_invitations(): void
    {
        // 테스트용 초대 생성
        UserInvitation::create([
            'tenant_id' => $this->tenant->id,
            'email' => 'invited@example.com',
            'role_id' => $this->role->id,
            'token' => UserInvitation::generateToken(),
            'status' => UserInvitation::STATUS_PENDING,
            'invited_by' => $this->user->id,
            'expires_at' => UserInvitation::calculateExpiresAt(),
        ]);

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

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

    public function test_can_filter_invitations_by_status(): void
    {
        // Pending 초대
        UserInvitation::create([
            'tenant_id' => $this->tenant->id,
            'email' => 'pending@example.com',
            'role_id' => $this->role->id,
            'token' => UserInvitation::generateToken(),
            'status' => UserInvitation::STATUS_PENDING,
            'invited_by' => $this->user->id,
            'expires_at' => UserInvitation::calculateExpiresAt(),
        ]);

        // Accepted 초대
        UserInvitation::create([
            'tenant_id' => $this->tenant->id,
            'email' => 'accepted@example.com',
            'role_id' => $this->role->id,
            'token' => UserInvitation::generateToken(),
            'status' => UserInvitation::STATUS_ACCEPTED,
            'invited_by' => $this->user->id,
            'expires_at' => UserInvitation::calculateExpiresAt(),
            'accepted_at' => now(),
        ]);

        $response = $this->authenticatedRequest('get', '/api/v1/users/invitations?status=pending');

        $response->assertStatus(200);
        $data = $response->json('data');
        if (is_array($data) && isset($data['data'])) {
            // Paginated response
            foreach ($data['data'] as $invitation) {
                $this->assertEquals('pending', $invitation['status']);
            }
        }
    }

    // ==================== Invite User Tests ====================

    public function test_can_invite_user(): void
    {
        $response = $this->authenticatedRequest('post', '/api/v1/users/invite', [
            'email' => 'newuser@example.com',
            'role_id' => $this->role->id,
            'message' => '테스트 초대 메시지입니다.',
        ]);

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

        $this->assertDatabaseHas('user_invitations', [
            'email' => 'newuser@example.com',
            'tenant_id' => $this->tenant->id,
            'status' => UserInvitation::STATUS_PENDING,
        ]);
    }

    public function test_cannot_invite_without_email(): void
    {
        $response = $this->authenticatedRequest('post', '/api/v1/users/invite', [
            'role_id' => $this->role->id,
        ]);

        $response->assertStatus(422);
    }

    public function test_cannot_invite_with_invalid_email(): void
    {
        $response = $this->authenticatedRequest('post', '/api/v1/users/invite', [
            'email' => 'not-an-email',
            'role_id' => $this->role->id,
        ]);

        $response->assertStatus(422);
    }

    // ==================== Cancel Invitation Tests ====================

    public function test_can_cancel_pending_invitation(): void
    {
        $invitation = UserInvitation::create([
            'tenant_id' => $this->tenant->id,
            'email' => 'cancel-test@example.com',
            'role_id' => $this->role->id,
            'token' => UserInvitation::generateToken(),
            'status' => UserInvitation::STATUS_PENDING,
            'invited_by' => $this->user->id,
            'expires_at' => UserInvitation::calculateExpiresAt(),
        ]);

        $response = $this->authenticatedRequest('delete', "/api/v1/users/invitations/{$invitation->id}");

        $response->assertStatus(200);

        $this->assertDatabaseHas('user_invitations', [
            'id' => $invitation->id,
            'status' => UserInvitation::STATUS_CANCELLED,
        ]);
    }

    // ==================== Resend Invitation Tests ====================

    public function test_can_resend_pending_invitation(): void
    {
        $invitation = UserInvitation::create([
            'tenant_id' => $this->tenant->id,
            'email' => 'resend-test@example.com',
            'role_id' => $this->role->id,
            'token' => UserInvitation::generateToken(),
            'status' => UserInvitation::STATUS_PENDING,
            'invited_by' => $this->user->id,
            'expires_at' => UserInvitation::calculateExpiresAt(),
        ]);

        $response = $this->authenticatedRequest('post', "/api/v1/users/invitations/{$invitation->id}/resend");

        $response->assertStatus(200);
    }

    // ==================== Accept Invitation Tests ====================

    public function test_can_accept_invitation_with_existing_user(): void
    {
        // 이미 존재하는 사용자용 초대 생성
        $existingEmail = 'existing-accept-'.uniqid().'@example.com';
        $existingUser = User::create([
            'user_id' => 'existing'.uniqid(),
            'name' => 'Existing User',
            'email' => $existingEmail,
            'password' => bcrypt('password123'),
        ]);

        $invitation = UserInvitation::create([
            'tenant_id' => $this->tenant->id,
            'email' => $existingEmail,
            'role_id' => $this->role->id,
            'token' => UserInvitation::generateToken(),
            'status' => UserInvitation::STATUS_PENDING,
            'invited_by' => $this->user->id,
            'expires_at' => UserInvitation::calculateExpiresAt(),
        ]);

        // 초대 수락은 인증 없이도 가능
        $response = $this->withHeaders([
            'X-API-KEY' => $this->apiKey,
            'Accept' => 'application/json',
        ])->postJson("/api/v1/users/invitations/{$invitation->token}/accept", [
            'name' => 'Existing User',
        ]);

        // 성공 또는 이미 존재하는 사용자 관련 처리
        // 401: 인증 필요, 200/201: 성공, 422: 검증 실패
        $this->assertContains($response->status(), [200, 201, 401, 422]);
    }

    public function test_cannot_accept_expired_invitation(): void
    {
        $invitation = UserInvitation::create([
            'tenant_id' => $this->tenant->id,
            'email' => 'expired-test@example.com',
            'role_id' => $this->role->id,
            'token' => UserInvitation::generateToken(),
            'status' => UserInvitation::STATUS_PENDING,
            'invited_by' => $this->user->id,
            'expires_at' => now()->subDay(), // 이미 만료됨
        ]);

        $response = $this->withHeaders([
            'X-API-KEY' => $this->apiKey,
            'Accept' => 'application/json',
        ])->postJson("/api/v1/users/invitations/{$invitation->token}/accept", [
            'name' => 'Test User',
            'password' => 'password123',
            'password_confirmation' => 'password123',
        ]);

        // 만료된 초대 수락 시도 - 400, 401, 422
        $this->assertContains($response->status(), [400, 401, 422]);
    }

    public function test_cannot_accept_cancelled_invitation(): void
    {
        $invitation = UserInvitation::create([
            'tenant_id' => $this->tenant->id,
            'email' => 'cancelled-test@example.com',
            'role_id' => $this->role->id,
            'token' => UserInvitation::generateToken(),
            'status' => UserInvitation::STATUS_CANCELLED,
            'invited_by' => $this->user->id,
            'expires_at' => UserInvitation::calculateExpiresAt(),
        ]);

        $response = $this->withHeaders([
            'X-API-KEY' => $this->apiKey,
            'Accept' => 'application/json',
        ])->postJson("/api/v1/users/invitations/{$invitation->token}/accept", [
            'name' => 'Test User',
            'password' => 'password123',
            'password_confirmation' => 'password123',
        ]);

        // 취소된 초대 수락 시도 - 400, 401, 404, 422
        $this->assertContains($response->status(), [400, 401, 404, 422]);
    }

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

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

        $response->assertStatus(401);
    }

    public function test_cannot_invite_without_authentication(): void
    {
        $response = $this->withHeaders([
            'X-API-KEY' => $this->apiKey,
            'Accept' => 'application/json',
        ])->postJson('/api/v1/users/invite', [
            'email' => 'test@example.com',
            'role_id' => $this->role->id,
        ]);

        $response->assertStatus(401);
    }
}
