<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Concerns\ResolvesAdminUserId;
use App\Http\Controllers\Controller;
use App\Jobs\Supplier\CsvReconcileJob;
use App\Models\Project;
use App\Models\SaasAdminAuditLog;
use App\Models\SupplierManualSyncQueue;
use App\Models\SupplierProject;
use App\Services\Supplier\Channel\SupplierProjectChannel;
use App\Services\Supplier\SupplierExportMode;
use App\Services\Supplier\SupplierPortalClient;
use App\Support\RussianRegions;
use App\Support\SystemSettings;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

/**
 * SaaS-admin → Интеграция с поставщиком: здоровье резервного CSV-канала (Путь 2).
 *
 * Spec: docs/superpowers/specs/2026-05-18-supplier-csv-reconcile-channel-design.md §4.4
 */
final class AdminSupplierIntegrationController extends Controller
{
    use ResolvesAdminUserId;

    private const HISTORY_LIMIT = 20;

    public function index(): JsonResponse
    {
        $rows = DB::connection('pgsql_supplier')
            ->table('supplier_csv_reconcile_log')
            ->orderByDesc('id')
            ->limit(self::HISTORY_LIMIT)
            ->get();

        $last = $rows->first();

        $webhookState = ($last !== null && $last->status === 'drift_alert') ? 'down' : 'live';

        return response()->json([
            'health' => [
                'last_run_at' => $last !== null ? ($last->finished_at ?? $last->started_at) : null,
                'last_status' => $last?->status,
                'drift_ratio' => $last !== null ? (float) $last->drift_ratio : null,
                'webhook_state' => $webhookState,
            ],
            'history' => $rows->map(fn ($r): array => [
                'started_at' => $r->started_at,
                'finished_at' => $r->finished_at,
                'window_start' => $r->window_start,
                'window_end' => $r->window_end,
                'status' => $r->status,
                'total_csv_rows' => (int) $r->total_csv_rows,
                'matched_count' => (int) $r->matched_count,
                'recovered_count' => (int) $r->recovered_count,
                'drift_ratio' => (float) $r->drift_ratio,
            ])->all(),
        ]);
    }

    public function reconcile(): JsonResponse
    {
        CsvReconcileJob::dispatch();

        return response()->json(['dispatched' => true]);
    }

    /**
     * Эпик 5: история вечерних заливок проектов поставщику (supplier_sync_runs).
     * SaaS-admin сверяет глазами, что заливка прошла ровно — от этого зависят
     * заказанные у поставщика лиды.
     */
    public function syncRuns(): JsonResponse
    {
        $rows = DB::connection('pgsql_supplier')
            ->table('supplier_sync_runs')
            ->orderByDesc('id')
            ->limit(self::HISTORY_LIMIT)
            ->get();

        return response()->json([
            'runs' => $rows->map(fn ($r): array => [
                'started_at' => $r->started_at,
                'finished_at' => $r->finished_at,
                'groups_total' => (int) $r->groups_total,
                'synced_ok' => (int) $r->synced_ok,
                'manual_queued' => (int) $r->manual_queued,
                'deferred' => (int) $r->deferred,
                'failed' => (int) $r->failed,
                'status' => $r->status,
            ])->all(),
        ]);
    }

    /**
     * Очередь яруса 3 резерва канала миграции проектов — pending-список для
     * оператора админ-экрана. Spec §4.6.
     */
    public function manualQueueIndex(): JsonResponse
    {
        $rows = SupplierManualSyncQueue::where('status', 'pending')
            ->orderByDesc('id')
            ->limit(100)
            ->get(['id', 'project_id', 'platform', 'operation', 'external_id', 'payload_snapshot', 'failure_reason', 'created_at']);

        return response()->json(['queue' => $rows]);
    }

    /**
     * Оператор вручную создал проект на портале → reconcile: сверяем через
     * listProjects(), ставим FK supplier_b{1,2,3}_project_id, помечаем resolved.
     * 409 если проект на портале не найден (оператор не создал / другие параметры).
     * Spec §4.6.
     */
    public function manualQueueResolve(int $id, Request $request, SupplierProjectChannel $channel): JsonResponse
    {
        $row = SupplierManualSyncQueue::findOrFail($id);
        if ($row->status !== 'pending') {
            return response()->json(['message' => 'already resolved or cancelled'], 409);
        }

        $payload = $row->payload_snapshot;
        $signalType = (string) ($payload['signal_type'] ?? '');
        $uniqueKey = (string) ($payload['unique_key'] ?? '');

        $found = null;
        foreach ($channel->listProjects() as $r) {
            if (
                ($r['platform'] ?? null) === $row->platform
                && ($r['signal_type'] ?? null) === $signalType
                && ($r['unique_key'] ?? null) === $uniqueKey
            ) {
                $found = (int) ($r['id'] ?? 0);
                break;
            }
        }

        if ($found === null) {
            return response()->json([
                'message' => 'Проект не найден на портале поставщика. Проверьте, что вы действительно его создали с теми же параметрами.',
            ], 409);
        }

        // FK projects.supplier_b{1,2,3}_project_id ведёт на local supplier_projects.id,
        // не на portal external_id. Find-or-create local row с verified external_id.
        $sp = SupplierProject::firstOrCreate(
            [
                'platform' => $row->platform,
                'signal_type' => $signalType,
                'unique_key' => $uniqueKey,
            ],
            [
                'supplier_external_id' => (string) $found,
                'current_limit' => 0,
                'current_workdays' => [1, 2, 3, 4, 5, 6, 7],
                'current_regions' => null,
                'sync_status' => 'ok',
            ],
        );

        Project::where('id', $row->project_id)->update([
            'supplier_'.strtolower($row->platform).'_project_id' => $sp->id,
        ]);

        $row->update([
            'status' => 'resolved',
            'resolved_by_user_id' => $request->user()->id,
            'resolved_at' => now(),
            'external_id' => (string) $found,
        ]);

        SaasAdminAuditLog::create([
            'admin_user_id' => $this->resolveAdminUserId($request, 'supplier-integration@system.stub', 'Supplier Integration Stub'),
            'action' => 'supplier_integration.manual_queue_resolved',
            'target_type' => 'manual_queue_item',
            'target_id' => $row->id,
            'payload_after' => ['external_id' => $found, 'platform' => $row->platform],
            'ip_address' => $request->ip() ?? '127.0.0.1',
            'user_agent' => $request->userAgent(),
            'requires_approval' => false,
        ]);

        return response()->json(['resolved' => true, 'external_id' => $found]);
    }

    /**
     * Глобальный режим экспорта проектов поставщику (Plan 4 Task 1).
     * Spec: docs/superpowers/specs/2026-05-20-project-migration-redesign-design.md §4.1.
     */
    public function getExportMode(): JsonResponse
    {
        return response()->json(['mode' => SupplierExportMode::current()]);
    }

    public function setExportMode(Request $request): JsonResponse
    {
        $data = $request->validate([
            'mode' => ['required', 'in:online,batch'],
        ]);

        $prevMode = DB::table('system_settings')->where('key', 'supplier_export_mode')->value('value');

        DB::table('system_settings')->updateOrInsert(
            ['key' => 'supplier_export_mode'],
            ['value' => $data['mode'], 'type' => 'string', 'updated_at' => now()],
        );

        SaasAdminAuditLog::create([
            'admin_user_id' => $this->resolveAdminUserId($request, 'supplier-integration@system.stub', 'Supplier Integration Stub'),
            'action' => 'supplier_integration.export_mode_set',
            'target_type' => 'system_setting',
            'target_id' => null,
            'payload_before' => $prevMode !== null ? ['mode' => $prevMode] : null,
            'payload_after' => ['mode' => $data['mode']],
            'ip_address' => $request->ip() ?? '127.0.0.1',
            'user_agent' => $request->userAgent(),
            'requires_approval' => false,
        ]);

        return response()->json(['mode' => $data['mode']]);
    }

    /**
     * Тумблер «Разблокировка смены источника» (флаг routing_match_by_snapshot).
     * GET — текущее состояние ВКЛ/ВЫКЛ для переключателя в админке.
     */
    public function getSourceEditFlag(): JsonResponse
    {
        return response()->json(['enabled' => SystemSettings::bool('routing_match_by_snapshot', false)]);
    }

    /**
     * POST — включить/выключить разблокировку смены источника (матч по слепку).
     * Пишет в system_settings (type=bool) + audit-журнал; основание не требуется
     * (дружелюбный тумблер для владельца, в отличие от общего edit-flow §settings).
     */
    public function setSourceEditFlag(Request $request): JsonResponse
    {
        $data = $request->validate([
            'enabled' => ['required', 'boolean'],
        ]);
        $enabled = (bool) $data['enabled'];

        $prev = DB::table('system_settings')->where('key', 'routing_match_by_snapshot')->value('value');

        DB::table('system_settings')->updateOrInsert(
            ['key' => 'routing_match_by_snapshot'],
            ['value' => $enabled ? 'true' : 'false', 'type' => 'bool', 'updated_at' => now()],
        );

        SaasAdminAuditLog::create([
            'admin_user_id' => $this->resolveAdminUserId($request, 'supplier-integration@system.stub', 'Supplier Integration Stub'),
            'action' => 'supplier_integration.source_edit_flag_set',
            'target_type' => 'system_setting',
            'target_id' => null,
            'payload_before' => $prev !== null ? ['enabled' => $prev] : null,
            'payload_after' => ['enabled' => $enabled ? 'true' : 'false'],
            'ip_address' => $request->ip() ?? '127.0.0.1',
            'user_agent' => $request->userAgent(),
            'requires_approval' => false,
        ]);

        return response()->json(['enabled' => $enabled]);
    }

    /**
     * Plan 4 Task 2: список supplier_projects + кто заказывал (через pivot →
     * projects → tenants) + дата последней поставки лида.
     */
    public function projectsIndex(): JsonResponse
    {
        $rows = DB::table('supplier_projects as sp')
            ->select([
                'sp.id',
                'sp.platform',
                'sp.signal_type',
                'sp.unique_key',
                'sp.subject_code',
                'sp.supplier_external_id',
                'sp.current_limit',
                'sp.inactive_since',
            ])
            ->orderBy('sp.unique_key')
            ->orderBy('sp.subject_code')
            ->orderBy('sp.platform')
            ->get();

        $projects = $rows->map(function ($sp): array {
            $orderers = DB::table('project_supplier_links as psl')
                ->join('projects as p', 'p.id', '=', 'psl.project_id')
                ->join('tenants as t', 't.id', '=', 'p.tenant_id')
                ->where('psl.supplier_project_id', $sp->id)
                ->distinct()
                ->pluck('t.organization_name')
                ->all();

            $lastDelivery = DB::table('supplier_leads')
                ->where('supplier_project_id', $sp->id)
                ->max('received_at');

            $subjectCode = $sp->subject_code !== null ? (int) $sp->subject_code : null;

            return [
                'id' => (int) $sp->id,
                'platform' => $sp->platform,
                'signal_type' => $sp->signal_type,
                'unique_key' => $sp->unique_key,
                'subject_code' => $subjectCode,
                'subject_name' => $subjectCode !== null
                    ? (RussianRegions::CODE_TO_NAME[$subjectCode] ?? null)
                    : 'РФ',
                'current_limit' => (int) $sp->current_limit,
                'supplier_external_id' => $sp->supplier_external_id,
                'inactive_since' => $sp->inactive_since,
                'orderers' => $orderers,
                'last_delivery_at' => $lastDelivery,
            ];
        });

        return response()->json(['projects' => $projects->all()]);
    }

    /**
     * Plan 4 Task 2: bulk-delete выбранных supplier_projects.
     * Сначала на портале (deleteProject), затем локально (pivot снимается CASCADE).
     * Сбой по строке — не прерывает batch, копится в failures[].
     */
    public function projectsDestroy(Request $request, SupplierPortalClient $client): JsonResponse
    {
        $data = $request->validate([
            'ids' => ['required', 'array', 'min:1'],
            'ids.*' => ['integer'],
        ]);

        $deleted = 0;
        $failures = [];

        foreach (SupplierProject::whereIn('id', $data['ids'])->get() as $sp) {
            try {
                if ($sp->supplier_external_id !== null) {
                    $client->deleteProject((int) $sp->supplier_external_id);
                }
                $sp->delete();
                $deleted++;
            } catch (\Throwable $e) {
                $failures[] = ['id' => $sp->id, 'error' => $e->getMessage()];
            }
        }

        SaasAdminAuditLog::create([
            'admin_user_id' => $this->resolveAdminUserId($request, 'supplier-integration@system.stub', 'Supplier Integration Stub'),
            'action' => 'supplier_integration.projects_destroyed',
            'target_type' => 'supplier_projects_bulk',
            'target_id' => null,
            'payload_before' => ['ids' => $data['ids']],
            'payload_after' => ['deleted' => $deleted, 'failures_count' => count($failures)],
            'ip_address' => $request->ip() ?? '127.0.0.1',
            'user_agent' => $request->userAgent(),
            'requires_approval' => false,
        ]);

        return response()->json(['deleted' => $deleted, 'failures' => $failures]);
    }
}
