<?php

namespace Tests\Feature;

use App\Models\Franchisee;
use App\Models\Program;
use App\Models\ProgramTranslation;
use App\Models\TranslateTemplate;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ProgramUpdatePreviewEndpointTest extends TestCase
{
    use RefreshDatabase;

    public function test_only_franchise_users_can_access_reset_preview_endpoint(): void
    {
        $superAdmin = User::factory()->create([
            'role' => 'super_admin',
            'franchisee_id' => null,
        ]);

        $program = Program::create([
            'slug' => 'robotics-reset',
            'is_global' => true,
            'is_enabled' => true,
            'order_no' => 1,
        ]);

        $response = $this
            ->actingAs($superAdmin, 'sanctum')
            ->getJson("/admin/programs/{$program->id}/reset-preview?language=hi");

        $response
            ->assertStatus(403)
            ->assertJson([
                'status' => false,
                'message' => 'Only franchise users can perform this action.',
            ]);
    }

    public function test_only_franchise_users_can_access_preview_endpoint(): void
    {
        $superAdmin = User::factory()->create([
            'role' => 'super_admin',
            'franchisee_id' => null,
        ]);

        $program = Program::create([
            'slug' => 'robotics',
            'is_global' => true,
            'is_enabled' => true,
            'order_no' => 1,
        ]);

        $response = $this
            ->actingAs($superAdmin, 'sanctum')
            ->getJson("/admin/programs/{$program->id}/update-preview?language=hi");

        $response
            ->assertStatus(403)
            ->assertJson([
                'status' => false,
                'message' => 'Only franchise users can perform this action.',
            ]);
    }

    public function test_it_returns_safe_response_when_global_translation_cannot_be_found(): void
    {
        [$franchise, $franchiseUser] = $this->createFranchiseAndUser();

        $globalProgram = Program::create([
            'slug' => 'coding',
            'is_global' => true,
            'is_enabled' => true,
            'order_no' => 1,
        ]);

        $franchiseProgram = Program::create([
            'franchisee_id' => $franchise->id,
            'parent_program_id' => $globalProgram->id,
            'slug' => 'coding',
            'is_global' => false,
            'is_enabled' => true,
            'order_no' => 1,
        ]);

        ProgramTranslation::create([
            'program_id' => $franchiseProgram->id,
            'franchisee_id' => $franchise->id,
            'language' => 'hi',
            'title' => 'स्थानीय कोडिंग',
            'status' => 'publish',
            'version' => 1,
            'adopted_from_global' => true,
            'source_global_translation_id' => null,
            'source_global_version' => 2,
        ]);

        $response = $this
            ->actingAs($franchiseUser, 'sanctum')
            ->getJson("/admin/programs/{$franchiseProgram->id}/update-preview?language=hi");

        $response
            ->assertOk()
            ->assertJsonPath('status', true)
            ->assertJsonPath('data.update_available', false)
            ->assertJsonPath('data.message', 'Latest global translation could not be found.')
            ->assertJsonPath('data.changes', []);
    }

    public function test_it_returns_diff_payload_for_outdated_franchise_translation(): void
    {
        [$franchise, $franchiseUser] = $this->createFranchiseAndUser();

        $globalProgram = Program::create([
            'slug' => 'mechanics',
            'is_global' => true,
            'is_enabled' => true,
            'order_no' => 2,
        ]);

        $sourceGlobalTranslation = ProgramTranslation::create([
            'program_id' => $globalProgram->id,
            'franchisee_id' => null,
            'language' => 'hi',
            'title' => 'ग्लोबल मैकेनिक्स',
            'age_range' => '39',
            'status' => 'publish',
            'version' => 3,
            'program_details' => [
                'created_for' => 'Created for kids',
            ],
        ]);

        $franchiseProgram = Program::create([
            'franchisee_id' => $franchise->id,
            'parent_program_id' => $globalProgram->id,
            'slug' => 'mechanics',
            'is_global' => false,
            'is_enabled' => true,
            'order_no' => 2,
        ]);

        ProgramTranslation::create([
            'program_id' => $franchiseProgram->id,
            'franchisee_id' => $franchise->id,
            'language' => 'hi',
            'title' => 'फ्रेंचाइज़ मैकेनिक्स',
            'age_range' => '34',
            'status' => 'publish',
            'version' => 1,
            'adopted_from_global' => true,
            'source_global_translation_id' => $sourceGlobalTranslation->id,
            'source_global_version' => 2,
            'last_local_edit_at' => now(),
            'program_details' => [
                'created_for' => 'Created for children',
            ],
        ]);

        $response = $this
            ->actingAs($franchiseUser, 'sanctum')
            ->getJson("/admin/programs/{$franchiseProgram->id}/update-preview?language=hi");

        $response
            ->assertOk()
            ->assertJsonPath('status', true)
            ->assertJsonPath('data.update_available', true)
            ->assertJsonPath('data.sync_state', 'locally_modified')
            ->assertJsonPath('data.language', 'hi')
            ->assertJsonPath('data.source_global_version', 2)
            ->assertJsonPath('data.latest_global_version', 3)
            ->assertJsonPath('data.has_local_changes', true)
            ->assertJsonPath('data.warning', 'Accepting this update will replace your current franchise content with the latest super admin version.');

        $changes = $response->json('data.changes');
        $byField = collect($changes)->keyBy('field');

        $this->assertArrayHasKey('age_range', $byField->all());
        $this->assertSame('34', (string) $byField['age_range']['old']);
        $this->assertSame('39', (string) $byField['age_range']['new']);
        $this->assertArrayHasKey('program_details.created_for', $byField->all());
    }

    private function createFranchiseAndUser(): array
    {
        $this->ensurePublishedTranslateTemplate('hi');

        $franchise = Franchisee::create([
            'name' => 'Franchise A',
            'franchise_domain' => 'franchise-a.example',
            'zoho_franchise_id' => 'ZOHO-A',
            'is_custom_domain' => false,
            'owner_name' => 'Owner A',
            'email' => 'owner-a@example.com',
            'phone' => '1234567890',
            'status' => 'active',
            'is_website_approved' => true,
            'language' => 'hi',
        ]);

        $user = User::factory()->create([
            'franchisee_id' => $franchise->id,
            'role' => 'franchise_admin',
        ]);

        return [$franchise, $user];
    }

    private function ensurePublishedTranslateTemplate(string $languageCode): void
    {
        $code = strtolower($languageCode);
        TranslateTemplate::query()->updateOrCreate(
            ['language_code' => $code],
            [
                'language_name' => strtoupper($code),
                'status' => 'Published',
                'published_at' => now(),
            ]
        );
    }
}
