<?php

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

/**
 * As many places to copy an invoice to as somebody wants, each with its own
 * record of what arrived.
 *
 * The first version had one path and one `exported_at` on the invoice. That
 * cannot say "on the office NAS, not yet on the off-site box", which is the
 * only interesting question once there is more than one destination — and the
 * reason for having more than one is precisely that any single one can fail.
 *
 * So: a row per destination, and a row per (invoice, destination) pair. An
 * invoice is not "exported"; it is on this target and not on that one, and the
 * sweep can tell the difference.
 */
return new class extends Migration
{
    public function up(): void
    {
        Schema::create('export_targets', function (Blueprint $table) {
            $table->id();
            $table->uuid()->unique();

            $table->string('name');

            // 'local' is a directory this machine can already write to — a NAS
            // mounted over NFS, a bind mount, a disk. The protocol is the
            // mount's business and deliberately not this application's.
            //
            // 'sftp' is for something reachable over the network with
            // credentials, a Hetzner Storage Box being the obvious one.
            $table->string('driver', 16)->default('local');

            // Where inside the target. For 'local' this is an absolute path
            // and the mount point itself; for 'sftp' the remote directory.
            $table->string('path');

            $table->string('host')->nullable();
            $table->unsignedSmallInteger('port')->nullable();
            $table->string('username')->nullable();

            // The KEY in the secret vault, never the secret. A password in a
            // settings table is a password in every database dump.
            $table->string('secret_key')->nullable();

            $table->boolean('active')->default(true);
            $table->timestamps();
        });

        Schema::create('invoice_exports', function (Blueprint $table) {
            $table->id();
            $table->foreignId('invoice_id')->constrained()->cascadeOnDelete();
            $table->foreignId('export_target_id')->constrained()->cascadeOnDelete();

            $table->timestamp('exported_at')->nullable();
            $table->string('error')->nullable();
            $table->unsignedSmallInteger('attempts')->default(0);
            $table->timestamps();

            // One row per pair, so a retry updates rather than accumulates.
            $table->unique(['invoice_id', 'export_target_id']);
            // The sweep asks for "not yet arrived" on every tick.
            $table->index('exported_at');
        });

        // Carry the single path over, so an installation that already set one
        // keeps its destination instead of quietly losing it.
        $existing = DB::table('app_settings')->where('key', 'invoices.export_path')->value('value');
        $path = trim((string) json_decode((string) $existing, true));

        if ($path !== '') {
            DB::table('export_targets')->insert([
                'uuid' => (string) Str::uuid(),
                'name' => 'Archiv',
                'driver' => 'local',
                'path' => $path,
                'active' => true,
                'created_at' => now(),
                'updated_at' => now(),
            ]);
        }

        Schema::table('invoices', function (Blueprint $table) {
            $table->dropIndex(['exported_at']);
            $table->dropColumn(['exported_at', 'export_error']);
        });
    }

    public function down(): void
    {
        Schema::table('invoices', function (Blueprint $table) {
            $table->timestamp('exported_at')->nullable();
            $table->string('export_error')->nullable();
            $table->index('exported_at');
        });

        Schema::dropIfExists('invoice_exports');
        Schema::dropIfExists('export_targets');
    }
};
