<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        $this->ensureAccountingTables();
        $this->ensureAccountingAccounts();

        if (Schema::hasTable('order_receipts')) {
            Schema::table('order_receipts', function (Blueprint $table) {
                if (! Schema::hasColumn('order_receipts', 'account_id')) {
                    $table->foreignId('account_id')->nullable()->after('payment_method')
                        ->constrained('accounting_accounts')->nullOnDelete();
                }
                if (! Schema::hasColumn('order_receipts', 'accounting_voucher_id')) {
                    $table->foreignId('accounting_voucher_id')->nullable()->after('account_id')
                        ->constrained('accounting_vouchers')->nullOnDelete();
                }
            });
        }

        if (! Schema::hasTable('customer_ledger_entries')) {
            Schema::create('customer_ledger_entries', function (Blueprint $table) {
                $table->id();
                $table->foreignId('order_receipt_id')->unique()->constrained('order_receipts')->cascadeOnDelete();
                $table->foreignId('order_id')->constrained()->cascadeOnDelete();
                $table->foreignId('user_id')->nullable()->constrained('users')->nullOnDelete();
                $table->string('entry_type', 40)->default('advance_payment');
                $table->decimal('debit', 24, 3)->default(0);
                $table->decimal('credit', 24, 3)->default(0);
                $table->decimal('balance_after', 24, 3)->default(0);
                $table->string('status', 30)->default('posted');
                $table->timestamp('entry_date');
                $table->text('note')->nullable();
                $table->foreignId('created_by_admin_id')->nullable()->constrained('admins')->nullOnDelete();
                $table->foreignId('voided_by_admin_id')->nullable()->constrained('admins')->nullOnDelete();
                $table->timestamp('voided_at')->nullable();
                $table->timestamps();

                $table->index(['user_id', 'entry_date']);
                $table->index(['order_id', 'status']);
            });
        }
    }

    public function down(): void
    {
        Schema::dropIfExists('customer_ledger_entries');

        if (Schema::hasTable('order_receipts')) {
            Schema::table('order_receipts', function (Blueprint $table) {
                if (Schema::hasColumn('order_receipts', 'accounting_voucher_id')) {
                    $table->dropConstrainedForeignId('accounting_voucher_id');
                }
                if (Schema::hasColumn('order_receipts', 'account_id')) {
                    $table->dropConstrainedForeignId('account_id');
                }
            });
        }
    }

    private function ensureAccountingTables(): void
    {
        if (! Schema::hasTable('accounting_accounts')) {
            Schema::create('accounting_accounts', function (Blueprint $table) {
                $table->id();
                $table->string('code', 60)->unique();
                $table->string('name')->index();
                $table->string('type', 40)->index();
                $table->foreignId('parent_id')->nullable()->constrained('accounting_accounts')->nullOnDelete();
                $table->boolean('is_system')->default(false);
                $table->boolean('is_active')->default(true);
                $table->timestamps();
            });
        }

        if (! Schema::hasTable('accounting_vouchers')) {
            Schema::create('accounting_vouchers', function (Blueprint $table) {
                $table->id();
                $table->string('voucher_no', 80)->unique();
                $table->string('source_type', 80)->index();
                $table->unsignedBigInteger('source_id')->nullable()->index();
                $table->string('source_fingerprint', 191)->nullable()->unique();
                $table->string('source_reference', 120)->nullable()->index();
                $table->string('sale_channel', 30)->nullable()->index();
                $table->string('status', 30)->default('posted')->index();
                $table->date('voucher_date')->index();
                $table->decimal('total_debit', 24, 8)->default(0);
                $table->decimal('total_credit', 24, 8)->default(0);
                $table->text('note')->nullable();
                $table->foreignId('created_by_admin_id')->nullable()->constrained('admins')->nullOnDelete();
                $table->foreignId('voided_by_admin_id')->nullable()->constrained('admins')->nullOnDelete();
                $table->timestamp('voided_at')->nullable();
                $table->timestamps();
            });
        }

        if (! Schema::hasTable('accounting_voucher_lines')) {
            Schema::create('accounting_voucher_lines', function (Blueprint $table) {
                $table->id();
                $table->foreignId('voucher_id')->constrained('accounting_vouchers')->cascadeOnDelete();
                $table->foreignId('account_id')->constrained('accounting_accounts')->restrictOnDelete();
                $table->decimal('debit', 24, 8)->default(0);
                $table->decimal('credit', 24, 8)->default(0);
                $table->string('party_type', 80)->nullable();
                $table->unsignedBigInteger('party_id')->nullable();
                $table->text('description')->nullable();
                $table->timestamps();
                $table->index(['party_type', 'party_id']);
            });
        }
    }

    private function ensureAccountingAccounts(): void
    {
        $now = now();
        $accounts = [
            ['code' => '1000', 'name' => 'Showroom Cash', 'type' => 'asset'],
            ['code' => '1010', 'name' => 'Bank/Card Receivable', 'type' => 'asset'],
            ['code' => '1020', 'name' => 'bKash Receivable', 'type' => 'asset'],
            ['code' => '1030', 'name' => 'Nagad Receivable', 'type' => 'asset'],
            ['code' => '1060', 'name' => 'Bank Account', 'type' => 'asset'],
            ['code' => '2200', 'name' => 'Customer Advance Liability', 'type' => 'liability'],
        ];

        foreach ($accounts as $account) {
            DB::table('accounting_accounts')->insertOrIgnore([
                $account + [
                    'is_system' => true,
                    'is_active' => true,
                    'updated_at' => $now,
                    'created_at' => $now,
                ],
            ]);
        }
    }
};
