<?php

namespace Tests\Feature;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Tests\TestCase;

class TenantIsolationGuardsTest extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();
        $this->withoutMiddleware();
        $this->ensureTenantIsolationSchema();
    }

    public function test_room_bulk_actions_rejects_room_from_another_hotel(): void
    {
        if (!$this->hasTables(['users', 'rooms', 'room_types'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 1001;
        $hotelB = 1002;
        $userId = $this->insertUser($hotelA);

        $roomTypeId = $this->insertRoomType($hotelA);
        $foreignRoomId = $this->insertRoom($hotelB, $roomTypeId, 'TST-ROOM-B');

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userId))
            ->withSession(['current_hotel_id' => $hotelA])
            ->post(route('rooms.bulk-actions'), [
                'room_ids' => [$foreignRoomId],
                'action' => 'update_status',
                'status' => 'available',
            ]);

        $response->assertSessionHasErrors('room_ids.0');
    }

    public function test_staff_bulk_deactivate_rejects_staff_from_another_hotel(): void
    {
        if (!$this->hasTables(['users', 'staff'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 2001;
        $hotelB = 2002;
        $userId = $this->insertUser($hotelA);
        $foreignStaffId = $this->insertStaff($hotelB, 'foreign.staff@example.com');

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userId))
            ->withSession(['current_hotel_id' => $hotelA])
            ->post(route('staff.bulk-deactivate'), [
                'staff_ids' => [$foreignStaffId],
            ]);

        $response->assertRedirect(route('staff.index'));
        $this->assertSame('active', DB::table('staff')->where('id', $foreignStaffId)->value('status'));
    }

    public function test_reservation_store_rejects_foreign_room_id_scaffold(): void
    {
        if (!$this->hasTables(['users', 'rooms', 'room_types', 'guests', 'reservations'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 3001;
        $hotelB = 3002;
        $userId = $this->insertUser($hotelA);
        $guestId = $this->insertGuest($hotelA, 'tenant.guest@example.com');

        $roomTypeId = $this->insertRoomType($hotelA);
        $foreignRoomId = $this->insertRoom($hotelB, $roomTypeId, 'TST-RSV-B');

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userId))
            ->withSession(['current_hotel_id' => $hotelA])
            ->post(route('reservations.store'), [
                'room_id' => $foreignRoomId,
                'check_in' => now()->addDay()->toDateString(),
                'check_out' => now()->addDays(2)->toDateString(),
                'adults' => 1,
                'children' => 0,
                'total_amount' => 150000,
                'paid_amount' => 0,
                'status' => 'confirmed',
                'payment_status' => 'pending',
                'guest_id' => $guestId,
            ]);

        $response->assertSessionHasErrors('room_id');
    }

    public function test_order_store_rejects_foreign_menu_item_scaffold(): void
    {
        if (!$this->hasTables(['users', 'menu_categories', 'menu_items'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 3501;
        $hotelB = 3502;
        $userA = $this->insertUser($hotelA);
        $categoryB = $this->insertMenuCategory($hotelB);
        $foreignMenuItemId = $this->insertMenuItem($hotelB, $categoryB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->post(route('pos.orders.store'), [
                'order_type' => 'takeaway',
                'items' => [
                    ['id' => $foreignMenuItemId, 'quantity' => 1],
                ],
            ]);

        $this->assertContains($response->getStatusCode(), [422, 500]);
        if (Schema::hasTable('orders')) {
            $this->assertSame(0, DB::table('orders')->count());
        }
    }

    public function test_maintenance_update_rejects_foreign_assigned_staff_scaffold(): void
    {
        if (
            !$this->hasTables(['users', 'staff', 'rooms', 'room_types', 'maintenances']) ||
            !Schema::hasColumn('maintenances', 'hotel_id')
        ) {
            $this->markTestSkipped('Required tables/columns are not available for this environment.');
        }

        $hotelA = 4001;
        $hotelB = 4002;
        $userId = $this->insertUser($hotelA);
        $roomTypeId = $this->insertRoomType($hotelA);
        $roomId = $this->insertRoom($hotelA, $roomTypeId, 'TST-MTN-A');
        $maintenanceId = $this->insertMaintenance($hotelA, $roomId, $userId);
        $foreignStaffId = $this->insertStaff($hotelB, 'foreign.maint.staff@example.com');

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userId))
            ->withSession(['current_hotel_id' => $hotelA])
            ->put(route('maintenance.update', ['maintenance' => $maintenanceId]), [
                'title' => 'Test maintenance',
                'description' => 'Update test',
                'room_id' => $roomId,
                'assigned_to' => $foreignStaffId,
                'priority' => 'medium',
                'status' => 'pending',
                'maintenance_type' => 'repair',
            ]);

        $this->assertContains($response->getStatusCode(), [302, 404, 422]);
        $this->assertNull(DB::table('maintenances')->where('id', $maintenanceId)->value('assigned_to'));
    }

    public function test_document_show_returns_404_for_cross_hotel_document_scaffold(): void
    {
        if (!$this->hasTables(['users', 'documents'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 5001;
        $hotelB = 5002;
        $userA = $this->insertUser($hotelA);
        $userB = $this->insertUser($hotelB);
        $foreignDocumentId = $this->insertDocument($userB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->get(route('documents.show', ['document' => $foreignDocumentId]));

        $response->assertRedirect(route('documents.index'));
    }

    public function test_accounting_assign_tags_rejects_foreign_tag_scaffold(): void
    {
        if (!$this->hasTables(['users', 'accounts', 'tags', 'account_tag'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 6001;
        $hotelB = 6002;
        $userA = $this->insertUser($hotelA);
        $accountId = $this->insertAccount($hotelA);
        $foreignTagId = $this->insertTag($hotelB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->post(route('accounting.accounts.tags', ['account' => $accountId]), [
                'tag_ids' => [$foreignTagId],
            ]);

        $this->assertContains($response->getStatusCode(), [302, 404, 422]);
        $this->assertSame(0, DB::table('account_tag')->where('account_id', $accountId)->count());
    }

    public function test_vendor_update_rejects_foreign_category_scaffold(): void
    {
        if (!$this->hasTables(['users', 'contacts'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 6501;
        $hotelB = 6502;
        $userA = $this->insertUser($hotelA);
        $foreignVendorId = $this->insertVendor($hotelB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->put(route('contacts.vendors.update', ['id' => $foreignVendorId]), [
                'company' => 'Mutated Company',
                'vendor_category' => 'Test',
                'first_name' => 'Foreign',
                'last_name' => 'Vendor',
            ]);

        $this->assertContains($response->getStatusCode(), [404, 500]);
        $this->assertNotSame('Mutated Company', DB::table('contacts')->where('id', $foreignVendorId)->value('company'));
    }

    public function test_menu_item_store_rejects_foreign_category_scaffold(): void
    {
        if (!$this->hasTables(['users', 'menu_categories', 'menu_items'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 7001;
        $hotelB = 7002;
        $userA = $this->insertUser($hotelA);
        $foreignCategoryId = $this->insertMenuCategory($hotelB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->post(route('menu-items.store'), [
                'name' => 'Isolation Item',
                'description' => 'test',
                'price' => 1000,
                'category_id' => $foreignCategoryId,
                'is_available' => 1,
            ]);

        $this->assertContains($response->getStatusCode(), [302, 422]);
        $this->assertSame(0, DB::table('menu_items')->where('name', 'Isolation Item')->count());
    }

    public function test_service_assign_rejects_foreign_service_id_scaffold(): void
    {
        if (!$this->hasTables(['users', 'services'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 8001;
        $hotelB = 8002;
        $userA = $this->insertUser($hotelA);
        $foreignServiceId = $this->insertService($hotelB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->post(route('services.assign'), [
                'service_id' => $foreignServiceId,
                'scheduled_date' => now()->toDateString(),
                'scheduled_time' => '10:00',
                'guest_type' => 'walk_in',
            ]);

        $this->assertSame(422, $response->getStatusCode());
    }

    public function test_leave_approve_blocks_cross_hotel_record_scaffold(): void
    {
        if (!$this->hasTables(['users', 'leaves'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 9001;
        $hotelB = 9002;
        $userA = $this->insertUser($hotelA);
        $foreignLeaveId = $this->insertLeave($hotelB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->post(route('leaves.approve', ['leave' => $foreignLeaveId]), [
                'approver_notes' => 'ok',
            ]);

        $this->assertContains($response->getStatusCode(), [302, 404, 500]);
        $this->assertSame('pending', DB::table('leaves')->where('id', $foreignLeaveId)->value('status'));
    }

    public function test_survey_invitation_store_rejects_foreign_guest_ids_scaffold(): void
    {
        if (!$this->hasTables(['users', 'surveys'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 9501;
        $hotelB = 9502;
        $userA = $this->insertUser($hotelA);
        $foreignSurveyId = $this->insertSurvey($hotelB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->get(route('surveys.invitations.statistics', ['survey' => $foreignSurveyId]));

        $this->assertContains($response->getStatusCode(), [302, 404, 500]);
    }

    public function test_inout_receipt_blocks_foreign_reservation(): void
    {
        if (!$this->hasTables(['users', 'reservations'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 9601;
        $hotelB = 9602;
        $userA = $this->insertUser($hotelA);
        $guestB = $this->insertGuest($hotelB, 'foreign.receipt@example.com');
        $roomTypeB = $this->insertRoomType($hotelB);
        $roomB = $this->insertRoom($hotelB, $roomTypeB, 'TST-REC-B');
        $reservationB = $this->insertReservationSimple($hotelB, $guestB, $roomB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->get(route('inout.receipt', ['reservationId' => $reservationB]));

        $this->assertContains($response->getStatusCode(), [302, 404, 500]);
    }

    public function test_survey_invitation_resend_blocks_foreign_invitation(): void
    {
        if (!$this->hasTables(['users', 'surveys', 'survey_invitations'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 9701;
        $hotelB = 9702;
        $userA = $this->insertUser($hotelA);
        $surveyB = $this->insertSurvey($hotelB);
        $invitationB = $this->insertSurveyInvitation($hotelB, $surveyB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->post(route('survey.invitation.resend', ['id' => $invitationB]));

        $response->assertRedirect();
        $this->assertSame('sent', DB::table('survey_invitations')->where('id', $invitationB)->value('status'));
    }

    public function test_inout_receipt_returns_404_when_invoice_missing(): void
    {
        if (!$this->hasTables(['users', 'reservations', 'invoices'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelId = 9801;
        $userId = $this->insertUser($hotelId);
        $guestId = $this->insertGuest($hotelId, 'missing.invoice@example.com');
        $roomTypeId = $this->insertRoomType($hotelId);
        $roomId = $this->insertRoom($hotelId, $roomTypeId, 'TST-REC-MISS');
        $reservationId = $this->insertReservationSimple($hotelId, $guestId, $roomId);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userId))
            ->withSession(['current_hotel_id' => $hotelId])
            ->get(route('inout.receipt', ['reservationId' => $reservationId]));

        $this->assertContains($response->getStatusCode(), [404, 500]);
    }

    public function test_inout_consolidated_invoice_blocks_foreign_reservation(): void
    {
        if (!$this->hasTables(['users', 'reservations'])) {
            $this->markTestSkipped('Required tables are not available for this environment.');
        }

        $hotelA = 9811;
        $hotelB = 9812;
        $userA = $this->insertUser($hotelA);
        $guestB = $this->insertGuest($hotelB, 'foreign.consolidated@example.com');
        $typeB = $this->insertRoomType($hotelB);
        $roomB = $this->insertRoom($hotelB, $typeB, 'TST-CONS-B');
        $reservationB = $this->insertReservationSimple($hotelB, $guestB, $roomB);

        $response = $this
            ->actingAs(\App\Models\User::query()->findOrFail($userA))
            ->withSession(['current_hotel_id' => $hotelA])
            ->get(route('inout.consolidated-invoice', ['reservationId' => $reservationB]));

        $this->assertContains($response->getStatusCode(), [302, 404, 500]);
    }

    public function test_survey_invitation_status_invalid_token_returns_404_json(): void
    {
        $response = $this->get(route('survey.invitation.status', ['token' => 'invalid-token']));

        $response->assertStatus(404);
    }

    public function test_survey_invitation_submit_invalid_token_redirects(): void
    {
        $response = $this->post(route('survey.invitation.submit', ['token' => 'invalid-token']), [
            'answers' => [],
        ]);

        $this->assertContains($response->getStatusCode(), [302, 404]);
    }

    private function hasTables(array $tables): bool
    {
        foreach ($tables as $table) {
            if (!Schema::hasTable($table)) {
                return false;
            }
        }

        return true;
    }

    private function insertUser(int $hotelId): int
    {
        $this->ensureHotelExists($hotelId);

        $data = [
            'first_name' => 'Test',
            'last_name' => 'User',
            'email' => 'tenant.user.' . uniqid() . '@example.com',
            'role' => 'admin',
            'password' => bcrypt('password'),
            'created_at' => now(),
            'updated_at' => now(),
        ];

        if (Schema::hasColumn('users', 'hotel_id')) {
            $data['hotel_id'] = $hotelId;
        }

        return (int) DB::table('users')->insertGetId($data);
    }

    private function insertRoomType(int $hotelId): int
    {
        $data = [
            'name' => 'Test Type ' . uniqid(),
            'description' => 'Test room type',
            'created_at' => now(),
            'updated_at' => now(),
        ];

        if (Schema::hasColumn('room_types', 'hotel_id')) {
            $data['hotel_id'] = $hotelId;
        }

        return (int) DB::table('room_types')->insertGetId($data);
    }

    private function insertRoom(int $hotelId, int $roomTypeId, string $roomNumber): int
    {
        $data = [
            'room_number' => $roomNumber . '-' . uniqid(),
            'room_type_id' => $roomTypeId,
            'price_per_night' => 120000,
            'capacity' => 2,
            'status' => 'available',
            'is_available' => 1,
            'created_at' => now(),
            'updated_at' => now(),
        ];

        if (Schema::hasColumn('rooms', 'hotel_id')) {
            $data['hotel_id'] = $hotelId;
        }

        return (int) DB::table('rooms')->insertGetId($data);
    }

    private function insertStaff(int $hotelId, string $email): int
    {
        $data = [
            'first_name' => 'Foreign',
            'last_name' => 'Staff',
            'email' => $email,
            'employee_id' => 'EMP-' . uniqid(),
            'status' => 'active',
            'created_at' => now(),
            'updated_at' => now(),
        ];

        if (Schema::hasColumn('staff', 'hotel_id')) {
            $data['hotel_id'] = $hotelId;
        }

        if (Schema::hasColumn('staff', 'department_id')) {
            $data['department_id'] = null;
        }

        if (Schema::hasColumn('staff', 'position_id')) {
            $data['position_id'] = null;
        }

        if (Schema::hasColumn('staff', 'hire_date')) {
            $data['hire_date'] = now()->toDateString();
        }

        return (int) DB::table('staff')->insertGetId($data);
    }

    private function insertGuest(int $hotelId, string $email): int
    {
        $data = [
            'first_name' => 'Test',
            'last_name' => 'Guest',
            'email' => $email . '.' . uniqid(),
            'created_at' => now(),
            'updated_at' => now(),
        ];

        if (Schema::hasColumn('guests', 'hotel_id')) {
            $data['hotel_id'] = $hotelId;
        }

        if (Schema::hasColumn('guests', 'status')) {
            $data['status'] = 'active';
        }

        return (int) DB::table('guests')->insertGetId($data);
    }

    private function insertMaintenance(int $hotelId, int $roomId, int $reportedBy): int
    {
        $data = [
            'title' => 'Test maintenance',
            'description' => 'Test description',
            'room_id' => $roomId,
            'reported_by' => $reportedBy,
            'priority' => 'medium',
            'status' => 'pending',
            'reported_date' => now()->toDateString(),
            'maintenance_type' => 'repair',
            'created_at' => now(),
            'updated_at' => now(),
        ];

        if (Schema::hasColumn('maintenances', 'hotel_id')) {
            $data['hotel_id'] = $hotelId;
        }

        if (Schema::hasColumn('maintenances', 'location')) {
            $data['location'] = 'Room test';
        }

        return (int) DB::table('maintenances')->insertGetId($data);
    }

    private function insertDocument(int $uploadedBy): int
    {
        $data = [
            'name' => 'Test Document ' . uniqid(),
            'file_name' => 'test.pdf',
            'file_path' => 'documents/test.pdf',
            'file_type' => 'pdf',
            'file_size' => 1234,
            'category' => 'other',
            'type' => 'other',
            'documentable_type' => 'custom',
            'documentable_id' => 0,
            'uploaded_by' => $uploadedBy,
            'created_at' => now(),
            'updated_at' => now(),
        ];

        return (int) DB::table('documents')->insertGetId($data);
    }

    private function insertAccount(int $hotelId): int
    {
        $data = [
            'hotel_id' => $hotelId,
            'code' => 'TST' . random_int(1000, 9999),
            'name' => 'Test Account',
            'account_type' => 'P',
            'normal_balance' => 'Dr',
            'is_active' => 1,
            'created_at' => now(),
            'updated_at' => now(),
        ];

        return (int) DB::table('accounts')->insertGetId($data);
    }

    private function insertTag(int $hotelId): int
    {
        return (int) DB::table('tags')->insertGetId([
            'hotel_id' => $hotelId,
            'name' => 'Tag ' . uniqid(),
            'group' => 'general',
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function ensureTenantIsolationSchema(): void
    {
        if (!Schema::hasTable('hotels')) {
            Schema::create('hotels', function (Blueprint $table) {
                $table->id();
                $table->string('name');
                $table->timestamps();
                $table->softDeletes();
            });
        }

        if (!Schema::hasTable('users')) {
            Schema::create('users', function (Blueprint $table) {
                $table->id();
                $table->string('first_name');
                $table->string('last_name');
                $table->string('email')->unique();
                $table->string('role')->default('admin');
                $table->string('password');
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->rememberToken();
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('room_types')) {
            Schema::create('room_types', function (Blueprint $table) {
                $table->id();
                $table->string('name');
                $table->text('description')->nullable();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('rooms')) {
            Schema::create('rooms', function (Blueprint $table) {
                $table->id();
                $table->string('room_number')->unique();
                $table->unsignedBigInteger('room_type_id')->nullable();
                $table->decimal('price_per_night', 10, 2)->default(0);
                $table->integer('capacity')->default(1);
                $table->string('status')->default('available');
                $table->boolean('is_available')->default(true);
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('staff')) {
            Schema::create('staff', function (Blueprint $table) {
                $table->id();
                $table->string('first_name')->nullable();
                $table->string('last_name')->nullable();
                $table->string('email')->nullable();
                $table->string('employee_id')->nullable();
                $table->string('status')->nullable();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('guests')) {
            Schema::create('guests', function (Blueprint $table) {
                $table->id();
                $table->string('first_name');
                $table->string('last_name');
                $table->string('email')->nullable();
                $table->string('status')->nullable();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('reservations')) {
            Schema::create('reservations', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('guest_id')->nullable();
                $table->unsignedBigInteger('room_id')->nullable();
                $table->unsignedBigInteger('created_by')->nullable();
                $table->date('check_in')->nullable();
                $table->date('check_out')->nullable();
                $table->decimal('total_amount', 10, 2)->default(0);
                $table->string('status')->default('pending');
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('maintenances')) {
            Schema::create('maintenances', function (Blueprint $table) {
                $table->id();
                $table->string('title');
                $table->text('description')->nullable();
                $table->unsignedBigInteger('room_id')->nullable();
                $table->unsignedBigInteger('assigned_to')->nullable();
                $table->unsignedBigInteger('reported_by')->nullable();
                $table->string('priority')->default('medium');
                $table->string('status')->default('pending');
                $table->date('reported_date')->nullable();
                $table->string('maintenance_type')->default('repair');
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('documents')) {
            Schema::create('documents', function (Blueprint $table) {
                $table->id();
                $table->string('name');
                $table->string('file_path');
                $table->string('file_name');
                $table->string('file_type');
                $table->integer('file_size')->default(0);
                $table->string('category');
                $table->string('type');
                $table->string('documentable_type')->nullable();
                $table->unsignedBigInteger('documentable_id')->nullable();
                $table->unsignedBigInteger('uploaded_by')->nullable();
                $table->timestamps();
                $table->softDeletes();
            });
        }

        if (!Schema::hasTable('document_shares')) {
            Schema::create('document_shares', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('document_id');
                $table->unsignedBigInteger('user_id');
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('accounts')) {
            Schema::create('accounts', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->string('code')->nullable();
                $table->string('name');
                $table->string('account_type')->default('P');
                $table->string('normal_balance')->default('Dr');
                $table->boolean('is_active')->default(true);
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('tags')) {
            Schema::create('tags', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('hotel_id');
                $table->string('name');
                $table->string('group')->nullable();
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('account_tag')) {
            Schema::create('account_tag', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('account_id');
                $table->unsignedBigInteger('tag_id');
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('menu_categories')) {
            Schema::create('menu_categories', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->string('name');
                $table->boolean('is_active')->default(true);
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('menu_items')) {
            Schema::create('menu_items', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->unsignedBigInteger('category_id')->nullable();
                $table->string('name');
                $table->text('description')->nullable();
                $table->decimal('price', 10, 2)->default(0);
                $table->boolean('is_available')->default(true);
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('services')) {
            Schema::create('services', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->string('name');
                $table->decimal('price', 10, 2)->default(0);
                $table->string('status')->default('active');
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('leaves')) {
            Schema::create('leaves', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->unsignedBigInteger('staff_id')->nullable();
                $table->unsignedBigInteger('leave_type_id')->nullable();
                $table->date('start_date')->nullable();
                $table->date('end_date')->nullable();
                $table->float('duration')->default(1);
                $table->text('reason')->nullable();
                $table->string('status')->default('pending');
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('contacts')) {
            Schema::create('contacts', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->string('type')->nullable();
                $table->string('company')->nullable();
                $table->string('vendor_category')->nullable();
                $table->string('first_name')->nullable();
                $table->string('last_name')->nullable();
                $table->string('email')->nullable();
                $table->string('phone')->nullable();
                $table->boolean('active')->default(true);
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('contact_histories')) {
            Schema::create('contact_histories', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('contact_id');
                $table->string('action')->nullable();
                $table->text('details')->nullable();
                $table->unsignedBigInteger('performed_by')->nullable();
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('surveys')) {
            Schema::create('surveys', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->string('title')->nullable();
                $table->string('status')->default('draft');
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('invoices')) {
            Schema::create('invoices', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->unsignedBigInteger('reservation_id')->nullable();
                $table->string('status')->nullable();
                $table->string('payment_status')->nullable();
                $table->decimal('total_amount', 10, 2)->default(0);
                $table->timestamps();
            });
        }

        if (!Schema::hasTable('survey_invitations')) {
            Schema::create('survey_invitations', function (Blueprint $table) {
                $table->id();
                $table->unsignedBigInteger('hotel_id')->nullable();
                $table->unsignedBigInteger('survey_id')->nullable();
                $table->unsignedBigInteger('guest_id')->nullable();
                $table->string('token')->nullable();
                $table->timestamp('sent_at')->nullable();
                $table->timestamp('expires_at')->nullable();
                $table->timestamp('responded_at')->nullable();
                $table->string('status')->default('sent');
                $table->string('recipient_email')->nullable();
                $table->string('recipient_name')->nullable();
                $table->string('recipient_type')->nullable();
                $table->timestamps();
            });
        }
    }

    private function ensureHotelExists(int $hotelId): void
    {
        if (!Schema::hasTable('hotels')) {
            return;
        }

        $exists = DB::table('hotels')->where('id', $hotelId)->exists();
        if (!$exists) {
            DB::table('hotels')->insert([
                'id' => $hotelId,
                'name' => 'Hotel ' . $hotelId,
                'created_at' => now(),
                'updated_at' => now(),
            ]);
        }
    }

    private function insertMenuCategory(int $hotelId): int
    {
        return (int) DB::table('menu_categories')->insertGetId([
            'hotel_id' => $hotelId,
            'name' => 'Cat ' . uniqid(),
            'is_active' => 1,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function insertService(int $hotelId): int
    {
        return (int) DB::table('services')->insertGetId([
            'hotel_id' => $hotelId,
            'name' => 'Service ' . uniqid(),
            'price' => 1000,
            'status' => 'active',
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function insertLeave(int $hotelId): int
    {
        return (int) DB::table('leaves')->insertGetId([
            'hotel_id' => $hotelId,
            'start_date' => now()->toDateString(),
            'end_date' => now()->addDay()->toDateString(),
            'duration' => 1,
            'reason' => 'test',
            'status' => 'pending',
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function insertMenuItem(int $hotelId, int $categoryId): int
    {
        return (int) DB::table('menu_items')->insertGetId([
            'hotel_id' => $hotelId,
            'category_id' => $categoryId,
            'name' => 'MenuItem ' . uniqid(),
            'description' => 'test',
            'price' => 1200,
            'is_available' => 1,
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function insertVendor(int $hotelId): int
    {
        return (int) DB::table('contacts')->insertGetId([
            'hotel_id' => $hotelId,
            'type' => 'vendor',
            'company' => 'Foreign Vendor ' . uniqid(),
            'vendor_category' => 'General',
            'first_name' => 'Foreign',
            'last_name' => 'Vendor',
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function insertSurvey(int $hotelId): int
    {
        return (int) DB::table('surveys')->insertGetId([
            'hotel_id' => $hotelId,
            'title' => 'Survey ' . uniqid(),
            'status' => 'active',
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }

    private function insertReservationSimple(int $hotelId, int $guestId, int $roomId): int
    {
        $data = [
            'created_at' => now(),
            'updated_at' => now(),
        ];

        $optional = [
            'hotel_id' => $hotelId,
            'reservation_number' => 'RSV-' . uniqid(),
            'guest_id' => $guestId,
            'room_id' => $roomId,
            'check_in' => now()->toDateString(),
            'check_out' => now()->addDay()->toDateString(),
            'adults' => 1,
            'children' => 0,
            'total_amount' => 100000,
            'paid_amount' => 0,
            'status' => 'confirmed',
            'payment_status' => 'pending',
        ];

        foreach ($optional as $column => $value) {
            if (Schema::hasColumn('reservations', $column)) {
                $data[$column] = $value;
            }
        }

        if (Schema::hasColumn('reservations', 'number_of_guests')) {
            $data['number_of_guests'] = 1;
        }

        return (int) DB::table('reservations')->insertGetId($data);
    }

    private function insertSurveyInvitation(int $hotelId, int $surveyId): int
    {
        return (int) DB::table('survey_invitations')->insertGetId([
            'hotel_id' => $hotelId,
            'survey_id' => $surveyId,
            'token' => (string) \Illuminate\Support\Str::uuid(),
            'status' => 'sent',
            'sent_at' => now(),
            'expires_at' => now()->addDays(7),
            'recipient_email' => 'invite.' . uniqid() . '@example.com',
            'recipient_name' => 'Invitee',
            'recipient_type' => 'guest',
            'created_at' => now(),
            'updated_at' => now(),
        ]);
    }
}

