<?php

declare(strict_types=1);

namespace Tests\Support\Imitation;

use App\Models\Project;
use App\Models\SupplierProject;
use App\Models\Tenant;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

/**
 * Seeder for the Phase 1 imitation harness.
 *
 * Creates the single-project matrix (36 projects) covering all combinations of:
 *   signal  ∈ {site, call}               — 2
 *   regions ∈ {[], [82], [82,83]}        — 3  (empty=all-RF, [82]=Москва, [82,83]=Москва+СПб)
 *   days    ∈ {127 (7 days), 31 (Mon-Fri)} — 2
 *   limit   ∈ {3, 30, 300}              — 3
 *   Total: 2 × 3 × 2 × 3 = 36
 *
 * All project names are prefixed IMIT-single-.
 * Topology helpers (G1/G2/G4) also use IMIT- prefix.
 *
 * Region codes follow ordinal 1..89 (constitutional order), NOT ГИБДД codes.
 * Москва = 82, Санкт-Петербург = 83 (verified via App\Support\RussianRegions::CODE_TO_NAME).
 *
 * Task 4 — Phase 1 Portal Client Imitation Harness.
 * Spec: docs/superpowers/specs/2026-06-03-portal-client-imitation-phase1-design.md
 * Plan: docs/superpowers/plans/2026-06-03-portal-client-imitation-phase1.md
 */
final class ImitationClientsSeeder
{
    /** Shared SupplierProject used by all matrix cells (B2 site-signal). */
    private ?SupplierProject $sharedSupplier = null;

    /**
     * Run the seeder: creates the 36-cell single-project matrix.
     * Topology helpers G1/G2/G4 (used by Task 13) are available as separate methods.
     */
    public function run(): void
    {
        $this->sharedSupplier = $this->makeSharedSupplierProject();
        $this->seedSingleProjectMatrix();
    }

    // -------------------------------------------------------------------------
    // Matrix seeding
    // -------------------------------------------------------------------------

    private function seedSingleProjectMatrix(): void
    {
        $signals = ['site', 'call'];
        // regions: empty = all-RF; [82] = Москва; [82, 83] = Москва + СПб
        $regions = [[], [82], [82, 83]];
        $dayMasks = [127, 31];
        $limits = [3, 30, 300];

        $i = 0;
        foreach ($signals as $signal) {
            foreach ($regions as $regionSet) {
                foreach ($dayMasks as $daysMask) {
                    foreach ($limits as $limit) {
                        $i++;
                        $this->makeSingleProjectCell(
                            index: $i,
                            signal: $signal,
                            regions: $regionSet,
                            daysMask: $daysMask,
                            limit: $limit,
                        );
                    }
                }
            }
        }
    }

    /**
     * Create one Tenant + User + Project + pivot link for a matrix cell.
     *
     * @param  array<int>  $regions  Ordinal subject codes 1..89 (empty = all-RF).
     */
    private function makeSingleProjectCell(
        int $index,
        string $signal,
        array $regions,
        int $daysMask,
        int $limit,
    ): void {
        $tenant = Tenant::factory()->create();
        User::factory()->create(['tenant_id' => $tenant->id]);

        // Unique signal identifier to avoid UNIQUE constraint violations.
        $uniqueSuffix = Str::random(6);
        $signalIdentifier = $signal === 'site'
            ? "imit-{$index}-{$uniqueSuffix}.test"
            : '7'.str_pad((string) (9000000000 + $index), 10, '0', STR_PAD_LEFT).$uniqueSuffix;

        // Pass regions as a PHP int[] — the PostgresIntArray Eloquent cast
        // converts it to the PostgreSQL literal '{82,83}' or '{}' in set().
        $project = $signal === 'site'
            ? Project::factory()
                ->asSiteSignal($signalIdentifier)
                ->create([
                    'name' => "IMIT-single-{$index}",
                    'tenant_id' => $tenant->id,
                    'regions' => $regions,
                    'delivery_days_mask' => $daysMask,
                    'daily_limit_target' => $limit,
                ])
            : Project::factory()
                ->asCallSignal($signalIdentifier)
                ->create([
                    'name' => "IMIT-single-{$index}",
                    'tenant_id' => $tenant->id,
                    'regions' => $regions,
                    'delivery_days_mask' => $daysMask,
                    'daily_limit_target' => $limit,
                ]);

        DB::table('project_supplier_links')->insert([
            'project_id' => $project->id,
            'supplier_project_id' => $this->sharedSupplier->id,
            'platform' => $this->sharedSupplier->platform,
            'subject_code' => null,
        ]);
    }

    // -------------------------------------------------------------------------
    // Shared supplier project factory
    // -------------------------------------------------------------------------

    /**
     * Create a shared SupplierProject (B2, site signal) used by all matrix cells.
     * B2 supports both site and call signals (no B1+sms constraint).
     */
    private function makeSharedSupplierProject(): SupplierProject
    {
        return SupplierProject::factory()->create([
            'platform' => 'B2',
            'signal_type' => 'site',
        ]);
    }

    // -------------------------------------------------------------------------
    // Topology helpers — used by Task 13 (TopologyMoneyIntakeTest)
    // -------------------------------------------------------------------------

    /**
     * G1 topology: one client (Tenant) with one Project linked to TWO different
     * SupplierProjects (B1 + B2).
     *
     * Validates that LeadRouter can route leads from multiple supplier sources
     * to the same project when the project is linked to multiple suppliers.
     *
     * @return array{tenant: Tenant, project: Project, suppliers: list<SupplierProject>}
     */
    public function seedG1(string $namePrefix = 'IMIT-G1'): array
    {
        $tenant = Tenant::factory()->create();
        User::factory()->create(['tenant_id' => $tenant->id]);

        $project = Project::factory()
            ->asSiteSignal("g1-{$namePrefix}-".Str::random(6).'.test')
            ->create([
                'name' => "{$namePrefix}-project",
                'tenant_id' => $tenant->id,
            ]);

        $supplier1 = SupplierProject::factory()->create(['platform' => 'B1', 'signal_type' => 'site']);
        $supplier2 = SupplierProject::factory()->create(['platform' => 'B2', 'signal_type' => 'site']);

        foreach ([$supplier1, $supplier2] as $supplier) {
            DB::table('project_supplier_links')->insert([
                'project_id' => $project->id,
                'supplier_project_id' => $supplier->id,
                'platform' => $supplier->platform,
                'subject_code' => null,
            ]);
        }

        return ['tenant' => $tenant, 'project' => $project, 'suppliers' => [$supplier1, $supplier2]];
    }

    /**
     * G2 topology: TWO clients (Tenants/Projects) linked to the SAME SupplierProject.
     *
     * Validates weighted lottery and fair distribution between competing clients
     * sharing a single supplier source.
     *
     * @param  array<string, mixed>  $overrides1  ProjectFactory overrides for client 1.
     * @param  array<string, mixed>  $overrides2  ProjectFactory overrides for client 2.
     * @return array{supplier: SupplierProject, projects: list<Project>, tenants: list<Tenant>}
     */
    public function seedG2(array $overrides1 = [], array $overrides2 = []): array
    {
        $supplier = SupplierProject::factory()->create(['platform' => 'B2', 'signal_type' => 'site']);

        $projects = [];
        $tenants = [];

        foreach ([$overrides1, $overrides2] as $idx => $overrides) {
            $tenant = Tenant::factory()->create();
            User::factory()->create(['tenant_id' => $tenant->id]);
            $tenants[] = $tenant;

            $project = Project::factory()
                ->asSiteSignal("g2-client-{$idx}-".Str::random(6).'.test')
                ->create(array_merge([
                    'name' => "IMIT-G2-client-{$idx}",
                    'tenant_id' => $tenant->id,
                ], $overrides));
            $projects[] = $project;

            DB::table('project_supplier_links')->insert([
                'project_id' => $project->id,
                'supplier_project_id' => $supplier->id,
                'platform' => $supplier->platform,
                'subject_code' => null,
            ]);
        }

        return ['supplier' => $supplier, 'projects' => $projects, 'tenants' => $tenants];
    }

    /**
     * G4 topology: one client with TWO Projects on the SAME SupplierProject,
     * each targeting a different region.
     *
     * Validates that LeadRouter dispatches leads to the project whose region
     * matches the lead's resolved subject code.
     *
     * @param  int  $regionA  Ordinal subject code for project A (e.g. 82 = Москва).
     * @param  int  $regionB  Ordinal subject code for project B (e.g. 83 = СПб).
     * @return array{supplier: SupplierProject, tenant: Tenant, projectA: Project, projectB: Project}
     */
    public function seedG4(int $regionA = 82, int $regionB = 83): array
    {
        $tenant = Tenant::factory()->create();
        User::factory()->create(['tenant_id' => $tenant->id]);

        $supplier = SupplierProject::factory()->create(['platform' => 'B2', 'signal_type' => 'site']);

        $uniqueA = Str::random(6);
        $uniqueB = Str::random(6);

        $projectA = Project::factory()
            ->asSiteSignal("g4-region-{$regionA}-{$uniqueA}.test")
            ->create([
                'name' => "IMIT-G4-region-{$regionA}",
                'tenant_id' => $tenant->id,
                'regions' => [$regionA],   // PHP int[] — PostgresIntArray cast handles conversion
            ]);

        $projectB = Project::factory()
            ->asSiteSignal("g4-region-{$regionB}-{$uniqueB}.test")
            ->create([
                'name' => "IMIT-G4-region-{$regionB}",
                'tenant_id' => $tenant->id,
                'regions' => [$regionB],   // PHP int[] — PostgresIntArray cast handles conversion
            ]);

        foreach ([$projectA, $projectB] as $project) {
            DB::table('project_supplier_links')->insert([
                'project_id' => $project->id,
                'supplier_project_id' => $supplier->id,
                'platform' => $supplier->platform,
                'subject_code' => null,
            ]);
        }

        return [
            'supplier' => $supplier,
            'tenant' => $tenant,
            'projectA' => $projectA,
            'projectB' => $projectB,
        ];
    }
}
