<?php

namespace App\Console\Commands;

use App\Enums\AppRole;
use App\Enums\PartnershipStatus;
use App\Models\Partnership;
use App\Models\User;
use App\Models\UserRole;
use App\Models\Workspace;
use App\Models\WorkspaceMember;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;

class ImportPartnershipsJson extends Command
{
    protected $signature = 'collabs:import-partnerships
                            {path : Absolute or project-relative path to partnerships JSON (array of rows)}
                            {--user= : User id to own new workspaces and receive membership (default: first user)}
                            {--dry-run : Parse and validate only; no database writes}';

    protected $description = 'Import partnership rows exported as JSON (e.g. Supabase) into this app';

    public function handle(): int
    {
        $rawPath = $this->argument('path');
        $path = File::exists($rawPath) ? $rawPath : base_path($rawPath);
        if (! File::exists($path)) {
            $this->error("File not found: {$rawPath}");

            return self::FAILURE;
        }

        $json = json_decode(File::get($path), true);
        if (! is_array($json)) {
            $this->error('JSON must be an array of partnership objects.');

            return self::FAILURE;
        }

        $dry = (bool) $this->option('dry-run');

        $userId = $this->option('user');
        $owner = $userId !== null
            ? User::query()->findOrFail((int) $userId)
            : User::query()->orderBy('id')->firstOrFail();

        $creatorMap = [];
        foreach ($json as $row) {
            if (! is_array($row) || empty($row['created_by'])) {
                continue;
            }
            $creatorMap[(string) $row['created_by']] = true;
        }

        if ($dry) {
            $this->info('[dry-run] Would import '.count($json).' partnerships.');
            $this->line('Workspaces (legacy UUIDs): '.count(array_unique(array_column($json, 'workspace_id'))));
            $this->line('Distinct creators: '.count($creatorMap));

            return self::SUCCESS;
        }

        DB::transaction(function () use ($json, $owner, &$creatorMap): void {
            $creatorMap = $this->ensureLegacyCreators(array_keys($creatorMap));

            $workspaceByLegacy = [];
            foreach (array_unique(array_filter(array_column($json, 'workspace_id'))) as $legacyWsId) {
                $workspaceByLegacy[$legacyWsId] = $this->ensureWorkspace((string) $legacyWsId, $owner);
            }

            foreach ($json as $row) {
                $this->importRow($row, $workspaceByLegacy, $creatorMap);
            }
        });

        $this->info('Imported '.count($json).' partnerships.');

        return self::SUCCESS;
    }

    /**
     * @param  list<string>  $legacyCreatorUuids
     * @return array<string, int>
     */
    private function ensureLegacyCreators(array $legacyCreatorUuids): array
    {
        $map = [];
        foreach ($legacyCreatorUuids as $uuid) {
            $email = 'legacy+'.Str::lower(Str::substr($uuid, 0, 8)).'@collabs.import';
            $user = User::query()->firstOrCreate(
                ['email' => $email],
                [
                    'name' => 'Imported ('.Str::substr($uuid, 0, 8).'…)',
                    'password' => Hash::make(Str::random(40)),
                ]
            );
            $map[$uuid] = (int) $user->id;
        }

        return $map;
    }

    private function ensureWorkspace(string $legacyUuid, User $owner): Workspace
    {
        $workspace = Workspace::query()->firstOrCreate(
            ['legacy_uuid' => $legacyUuid],
            [
                'name' => 'Imported board '.Str::substr($legacyUuid, 0, 8),
                'owner_id' => $owner->id,
            ]
        );

        WorkspaceMember::query()->firstOrCreate(
            [
                'workspace_id' => $workspace->id,
                'user_id' => $owner->id,
            ],
            ['role' => AppRole::Influencer->value]
        );

        UserRole::query()->firstOrCreate(
            [
                'user_id' => $owner->id,
                'role' => AppRole::Influencer->value,
            ]
        );

        return $workspace;
    }

    /**
     * @param  array<string, Workspace>  $workspaceByLegacy
     * @param  array<string, int>  $creatorMap
     */
    private function importRow(array $row, array $workspaceByLegacy, array $creatorMap): void
    {
        $legacyId = (string) $row['id'];
        $legacyWs = (string) $row['workspace_id'];
        $workspace = $workspaceByLegacy[$legacyWs] ?? null;
        if ($workspace === null) {
            throw new \InvalidArgumentException('Row missing workspace_id: '.$legacyId);
        }

        $status = PartnershipStatus::from((string) $row['status']);
        $createdBy = isset($row['created_by']) ? ($creatorMap[(string) $row['created_by']] ?? null) : null;

        $inclusions = $this->decodeInclusions($row['inclusions'] ?? null);

        $attrs = [
            'workspace_id' => $workspace->id,
            'restaurant_name' => (string) $row['restaurant_name'],
            'instagram_handle' => $row['instagram_handle'] !== null ? (string) $row['instagram_handle'] : null,
            'instagram_url' => $row['instagram_url'] !== null ? (string) $row['instagram_url'] : null,
            'status' => $status,
            'scheduled_date' => $row['scheduled_date'] !== null && $row['scheduled_date'] !== ''
                ? $row['scheduled_date']
                : null,
            'scheduled_time' => $row['scheduled_time'] !== null && $row['scheduled_time'] !== ''
                ? (string) $row['scheduled_time']
                : null,
            'inclusions' => $inclusions,
            'guests' => isset($row['guests']) && $row['guests'] !== null && $row['guests'] !== ''
                ? (int) $row['guests']
                : null,
            'notes' => $row['notes'] !== null ? (string) $row['notes'] : null,
            'location' => $row['location'] !== null ? (string) $row['location'] : null,
            'post_url' => $row['post_url'] !== null ? (string) $row['post_url'] : null,
            'created_by' => $createdBy,
            'managed_by_restaurant' => isset($row['managed_by_restaurant']) && $row['managed_by_restaurant'] !== null && $row['managed_by_restaurant'] !== ''
                ? (int) $row['managed_by_restaurant']
                : null,
        ];

        if (! empty($row['created_at'])) {
            $attrs['created_at'] = $row['created_at'];
        }
        if (! empty($row['updated_at'])) {
            $attrs['updated_at'] = $row['updated_at'];
        }

        Partnership::withoutEvents(function () use ($legacyId, $attrs): void {
            Partnership::query()->updateOrCreate(
                ['legacy_uuid' => $legacyId],
                $attrs
            );
        });
    }

    private function decodeInclusions(mixed $raw): ?array
    {
        if ($raw === null || $raw === '') {
            return null;
        }
        if (is_array($raw)) {
            return $raw === [] ? [] : $raw;
        }
        if (is_string($raw)) {
            $decoded = json_decode($raw, true);
            if (json_last_error() !== JSON_ERROR_NONE) {
                return null;
            }

            return is_array($decoded) ? $decoded : null;
        }

        return null;
    }
}
