<?php

namespace App\Console\Commands;

use App\Services\DataverseSchemaService;
use Illuminate\Console\Command;
use Throwable;

/**
 * Idempotently add the per-credit-account storage-config columns to the
 * crf61_cr6f2_ocrcredits table:
 *   • cr6f2_storagetype   — which storage backend (sharepoint | server; googledrive reserved)
 *   • cr6f2_storageconfig — JSON blob of the backend-specific settings
 *
 * Phase 1 is config-only: these columns just hold the settings; the upload/OCR
 * pipeline is wired to actually use them in a later phase. The two columns use
 * the cr6f2_ prefix to match the table's existing routing fields
 * (cr6f2_sitename / cr6f2_defaultserverip).
 *
 * Default is a dry run; pass --apply to mutate the schema.
 */
class ExtendOcrCreditStorageSchema extends Command
{
    protected $signature = 'ocrcredit:extend-storage-schema
                            {--apply : Actually create the columns (default: dry run)}
                            {--solution= : Add the columns to this unmanaged solution (default: Common Data Service Default Solution)}';

    protected $description = 'Add per-credit-account storage config columns (cr6f2_storagetype, cr6f2_storageconfig) to crf61_cr6f2_ocrcredits';

    private const ENTITY = 'crf61_cr6f2_ocrcredits';

    public function handle(DataverseSchemaService $schema): int
    {
        $apply    = (bool) $this->option('apply');
        $solution = $this->option('solution') ?: null;

        $columns = [
            'cr6f2_storagetype'   => fn() => $schema->stringAttribute('cr6f2_storagetype', 'Storage Type', 20, 'Storage backend for this credit account: sharepoint | server (googledrive reserved for future).'),
            'cr6f2_storageconfig' => fn() => $schema->memoAttribute('cr6f2_storageconfig', 'Storage Config', 100000, 'JSON of the backend-specific storage settings (SharePoint tenant/client/site/folder or server host/path/credentials).'),
        ];

        $this->line('  <fg=cyan>Environment:</> ' . config('dataverse.environment_url'));
        $this->line('  <fg=cyan>Entity:</>      ' . self::ENTITY);
        $this->line('  <fg=cyan>Solution:</>    ' . ($solution ?? '(default)'));
        $this->line('  <fg=cyan>Mode:</>        ' . ($apply ? 'APPLY' : 'dry run'));
        $this->newLine();

        try {
            $existing = array_flip($schema->listAttributeLogicalNames(self::ENTITY));
        } catch (Throwable $e) {
            $this->error('  ✗ Could not read existing attributes: ' . $e->getMessage());
            return Command::FAILURE;
        }

        $created  = 0;
        $skipped  = 0;
        $toCreate = 0;

        foreach ($columns as $logical => $bodyBuilder) {
            if (isset($existing[strtolower($logical)])) {
                $this->line("  <fg=gray>·</> {$logical} <fg=gray>(already exists, skipped)</>");
                $skipped++;
                continue;
            }

            $toCreate++;
            if (!$apply) {
                $this->line("  <fg=green>+</> {$logical} <fg=gray>(would create)</>");
                continue;
            }

            try {
                $schema->createAttribute(self::ENTITY, $bodyBuilder(), $solution);
                $this->line("  <fg=green>✓</> {$logical} <fg=green>created</>");
                $created++;
            } catch (Throwable $e) {
                if ($this->looksLikePermissionError($e)) {
                    $this->newLine();
                    $this->error('  ✗ Schema mutation denied — service principal is missing the System Customizer role.');
                    $this->line('    Service principal: <fg=yellow>' . config('dataverse.client_id') . '</>');
                    $this->line('    Grant in Power Platform Admin Center → Environments → Settings → Users + permissions → Application users.');
                    $this->line('    Raw error: ' . $e->getMessage());
                    return Command::FAILURE;
                }
                $this->error("  ✗ {$logical}: " . $e->getMessage());
                return Command::FAILURE;
            }
        }

        $this->newLine();
        if ($apply) {
            $this->info("Done. Created {$created}, skipped {$skipped} (already present).");
        } else {
            $this->info("Dry run complete. {$toCreate} column(s) would be created, {$skipped} already exist.");
            $this->line('Re-run with <fg=yellow>--apply</> to mutate the schema.');
        }

        return Command::SUCCESS;
    }

    private function looksLikePermissionError(Throwable $e): bool
    {
        $m = $e->getMessage();
        return str_contains($m, '[403]')
            || str_contains($m, 'prvCreateAttribute')
            || str_contains($m, '0x80040220')
            || str_contains($m, 'Principal user is missing');
    }
}
