<?php

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

/**
 * Collapses the old Company tab and the old Invoice-template tab into a single
 * `invoice` section holding exactly the nine business fields the landlord is
 * asked for, plus a repeatable branch list.
 *
 * The six previous `invoice_*` columns (bank / bank_name / bank_acc /
 * footer_phone / footer_addr / note) were never read by anything — no tenant
 * side consumer existed, because no invoice print existed. They are dropped
 * rather than carried, except that footer_addr/footer_phone described a real
 * second premises and so are carried into `invoice_branches` instead of lost.
 *
 * New columns are added and back-filled before the old ones are dropped, so the
 * change is data-preserving and needs no rename support from the driver.
 */
return new class extends Migration
{
    /** The nine landlord-managed business fields, plus the branch list. */
    private const ADDED = [
        'invoice_business_name',
        'invoice_business_logo',
        'invoice_business_address',
        'invoice_business_phone',
        'invoice_business_email',
        'invoice_business_website',
        'invoice_business_registration_no',
        'invoice_tax_registration_no',
        'invoice_business_description',
        'invoice_branches',
    ];

    private const DROPPED = [
        'invoice_bank',
        'invoice_bank_name',
        'invoice_bank_acc',
        'invoice_footer_phone',
        'invoice_footer_addr',
        'invoice_note',
        'company_name',
        'company_registration_no',
        'company_email',
        'company_phone',
        'company_address',
    ];

    public function up(): void
    {
        Schema::table('tenant_settings', function (Blueprint $table) {
            $table->string('invoice_business_name')->nullable();
            $table->string('invoice_business_logo')->nullable();
            $table->text('invoice_business_address')->nullable();
            $table->string('invoice_business_phone')->nullable();
            $table->string('invoice_business_email')->nullable();
            $table->string('invoice_business_website')->nullable();
            $table->string('invoice_business_registration_no')->nullable();
            $table->string('invoice_tax_registration_no')->nullable();
            $table->text('invoice_business_description')->nullable();
            $table->json('invoice_branches')->nullable();
        });

        $this->carryOverExistingSettings();

        Schema::table('tenant_settings', function (Blueprint $table) {
            $table->dropColumn(self::DROPPED);
        });
    }

    public function down(): void
    {
        Schema::table('tenant_settings', function (Blueprint $table) {
            $table->string('company_name')->nullable();
            $table->string('company_registration_no')->nullable();
            $table->string('company_email')->nullable();
            $table->json('company_phone')->nullable();
            $table->text('company_address')->nullable();

            $table->string('invoice_bank')->nullable();
            $table->string('invoice_bank_name')->nullable();
            $table->string('invoice_bank_acc')->nullable();
            $table->string('invoice_footer_phone')->nullable();
            $table->string('invoice_footer_addr')->nullable();
            $table->text('invoice_note')->nullable();
        });

        DB::table('tenant_settings')->orderBy('id')->each(function (object $row): void {
            DB::table('tenant_settings')->where('id', $row->id)->update([
                'company_name' => $row->invoice_business_name,
                'company_registration_no' => $row->invoice_business_registration_no,
                'company_email' => $row->invoice_business_email,
                'company_address' => $row->invoice_business_address,
                'company_phone' => $this->encodePhones($row->invoice_business_phone),
            ]);
        });

        Schema::table('tenant_settings', function (Blueprint $table) {
            $table->dropColumn(self::ADDED);
        });
    }

    /**
     * Company identity moves across as-is; the logo defaults to the branding
     * logo so a print has a mark without re-uploading one. The old footer
     * address/phone pair was a second premises, so it becomes the first entry
     * in the new branch list rather than being discarded.
     */
    private function carryOverExistingSettings(): void
    {
        DB::table('tenant_settings')->orderBy('id')->each(function (object $row): void {
            $branch = array_filter([
                'label' => 'Branch',
                'address' => $row->invoice_footer_addr ?? null,
                'phone' => $row->invoice_footer_phone ?? null,
            ], fn ($value): bool => $value !== null && $value !== '');

            $hasBranch = isset($branch['address']) || isset($branch['phone']);

            DB::table('tenant_settings')->where('id', $row->id)->update([
                'invoice_business_name' => $row->company_name ?? null,
                'invoice_business_logo' => $row->branding_logo_url ?? null,
                'invoice_business_address' => $row->company_address ?? null,
                'invoice_business_phone' => $this->firstPhone($row->company_phone ?? null),
                'invoice_business_email' => $row->company_email ?? null,
                'invoice_business_registration_no' => $row->company_registration_no ?? null,
                'invoice_branches' => $hasBranch ? json_encode([$branch]) : null,
            ]);
        });
    }

    /** `company_phone` was a JSON array; the new field is a single line. */
    private function firstPhone(?string $encoded): ?string
    {
        if ($encoded === null || $encoded === '') {
            return null;
        }

        $phones = json_decode($encoded, true);

        if (! is_array($phones)) {
            return $encoded;
        }

        $phones = array_values(array_filter($phones, fn ($p): bool => filled($p)));

        return $phones === [] ? null : implode(', ', $phones);
    }

    private function encodePhones(?string $phone): ?string
    {
        if ($phone === null || $phone === '') {
            return null;
        }

        return json_encode(array_map('trim', explode(',', $phone)));
    }
};
