<?php

namespace Tests\Feature;

use App\Http\Controllers\Admin\ArticleController;
use App\Models\SiteSyncOutbox;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;

class MansionSiteSyncStatusUiTest extends TestCase
{
    private const BUILDING_ID = 200;

    protected function setUp(): void
    {
        parent::setUp();
        config()->set('database.default', 'sqlite');
        config()->set('database.connections.sqlite.database', ':memory:');
        DB::purge('sqlite');
        Schema::create('site_sync_outboxes', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->unsignedInteger('company_id');
            $table->unsignedBigInteger('building_id');
            $table->string('operation', 64);
            $table->longText('payload');
            $table->string('status');
            $table->unsignedInteger('retry_count')->default(0);
            $table->timestamps();
        });
        session()->start();
    }

    public function test_successful_status_shows_no_warning_or_retry_action(): void
    {
        $html = $this->renderStatus(SiteSyncOutbox::STATUS_SUCCEEDED);

        $this->assertNotContains('サイト再同期待ち', $html);
        $this->assertNotContains('サイト同期失敗', $html);
        $this->assertNotContains('サイトへ再同期', $html);
    }

    public function test_pending_status_shows_safe_message_and_csrf_protected_retry_form(): void
    {
        $html = $this->renderStatus(SiteSyncOutbox::STATUS_PENDING, [
            'siteSyncLastError' => 'Authorization: Bearer raw-secret',
            'siteSyncPayload' => ['private' => 'raw-payload-secret'],
        ]);

        $this->assertContains('サイト再同期待ち', $html);
        $this->assertContains('物件情報の保存は完了しましたが、サイトへの反映に失敗しました。自動的に再送します。必要に応じて「サイトへ再同期」を実行してください。', $html);
        $this->assertContains('method="POST"', $html);
        $this->assertContains('name="_token"', $html);
        $this->assertContains(route('mansion.site-sync.retry', ['id' => self::BUILDING_ID]), $html);
        $this->assertNotContains('raw-secret', $html);
        $this->assertNotContains('raw-payload-secret', $html);
    }

    public function test_failed_status_shows_failure_and_retry_button(): void
    {
        $html = $this->renderStatus(SiteSyncOutbox::STATUS_FAILED);

        $this->assertContains('サイト同期失敗', $html);
        $this->assertContains('サイトへ再同期', $html);
        $this->assertContains('自動再送に失敗しました。', $html);
        $this->assertNotContains('自動的に再送します。', $html);
    }

    public function test_processing_status_shows_feedback_without_a_duplicate_retry_button(): void
    {
        session()->flash('site_sync_warning', 'Site synchronization is already processing.');

        $html = $this->renderStatus(SiteSyncOutbox::STATUS_PROCESSING);

        $this->assertContains('サイト再同期処理中', $html);
        $this->assertContains('現在サイトへの再同期を実行中です。', $html);
        $this->assertNotContains('Site synchronization is already processing.', $html);
        $this->assertNotContains('<button', $html);
    }

    public function test_manual_success_message_suppresses_stale_failure_indicator(): void
    {
        session()->flash('site_sync_success', 'サイトへの再同期が完了しました。');

        $html = $this->renderStatus(SiteSyncOutbox::STATUS_FAILED);

        $this->assertContains('サイトへの再同期が完了しました。', $html);
        $this->assertNotContains('サイト再同期待ち', $html);
        $this->assertNotContains('サイト同期失敗', $html);
        $this->assertNotContains('サイトへ再同期', $html);
    }

    public function test_status_lookup_is_scoped_by_company_building_and_operation(): void
    {
        $this->statusRow(10, self::BUILDING_ID, 'edit_mansion', SiteSyncOutbox::STATUS_PENDING);
        $this->statusRow(11, self::BUILDING_ID, 'edit_mansion', SiteSyncOutbox::STATUS_FAILED);
        $this->statusRow(10, 201, 'edit_mansion', SiteSyncOutbox::STATUS_FAILED);
        $this->statusRow(10, self::BUILDING_ID, 'other_operation', SiteSyncOutbox::STATUS_FAILED);
        $controller = new class extends ArticleController {
            public function statusFor(int $companyId, int $buildingId): ?string
            {
                return $this->getMansionSiteSyncStatus($companyId, $buildingId);
            }
        };

        $this->assertSame(
            SiteSyncOutbox::STATUS_PENDING,
            $controller->statusFor(10, self::BUILDING_ID)
        );
    }

    private function statusRow(int $companyId, int $buildingId, string $operation, string $status): void
    {
        DB::table('site_sync_outboxes')->insert([
            'company_id' => $companyId,
            'building_id' => $buildingId,
            'operation' => $operation,
            'payload' => '{}',
            'status' => $status,
            'retry_count' => 0,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function renderStatus(?string $status, array $additional = []): string
    {
        return view('admin.objects.components.mansion-site-sync-status', array_merge([
            'siteSyncStatus' => $status,
            'buildingId' => self::BUILDING_ID,
        ], $additional))->render();
    }
}
