<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Carbon\CarbonImmutable;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

/**
 * SaaS-admin incidents-log lookup для AdminIncidentsView.
 *
 * Чтение `incidents_log` (schema §9). На MVP без auth (saas-admin SSO ⏸ Б-1).
 *
 * Возвращает list инцидентов с дренажным фильтром по type/severity и summary
 * статистикой (open/investigating/RKN-pending). `incident_id` — derived from
 * `id` в формате `INC-YYYY-MMDD-NNNN` (frontend ожидает строковый код).
 */
class AdminIncidentsController extends Controller
{
    /** GET /api/admin/incidents?type=&severity=&unresolved_only=&limit=&offset= */
    public function index(Request $request): JsonResponse
    {
        $type = (string) $request->query('type', '');
        $severity = (string) $request->query('severity', '');
        $unresolvedOnly = $request->boolean('unresolved_only');
        $limit = max(1, min(500, (int) $request->query('limit', '100')));
        $offset = max(0, (int) $request->query('offset', '0'));

        $query = DB::table('incidents_log');

        if ($type !== '') {
            $query->where('type', $type);
        }
        if ($severity !== '') {
            $query->where('severity', $severity);
        }
        if ($unresolvedOnly) {
            $query->whereNull('resolved_at');
        }

        $total = (clone $query)->count();

        $rows = $query
            ->orderByDesc('started_at')
            ->orderByDesc('id')
            ->limit($limit)
            ->offset($offset)
            ->get();

        return response()->json([
            'incidents' => $rows->map(fn ($r) => [
                'id' => (int) $r->id,
                'incident_id' => $this->formatIncidentId($r),
                'type' => $r->type,
                'severity' => $r->severity,
                'summary' => $r->summary,
                'started_at' => CarbonImmutable::parse($r->started_at)->toIso8601String(),
                'detected_at' => CarbonImmutable::parse($r->detected_at)->toIso8601String(),
                'resolved_at' => $r->resolved_at !== null
                    ? CarbonImmutable::parse($r->resolved_at)->toIso8601String()
                    : null,
                'status' => $this->deriveStatus($r),
                'affected_tenants_count' => is_array($r->affected_tenant_ids)
                    ? count($r->affected_tenant_ids)
                    : (is_string($r->affected_tenant_ids) ? $this->parsePgArray($r->affected_tenant_ids) : 0),
                'affected_users_count' => $r->affected_users_count !== null ? (int) $r->affected_users_count : null,
                'rkn_notified' => $r->rkn_notified_at !== null,
                'rkn_notified_at' => $r->rkn_notified_at !== null
                    ? CarbonImmutable::parse($r->rkn_notified_at)->toIso8601String()
                    : null,
                'rkn_deadline_at' => $r->type === 'data_breach' && $r->rkn_notified_at === null
                    ? CarbonImmutable::parse($r->detected_at)->addHours(24)->toIso8601String()
                    : null,
            ]),
            'total' => $total,
            'limit' => $limit,
            'offset' => $offset,
            'summary' => $this->computeSummary(),
        ]);
    }

    /** Уникальный человеко-читаемый ID: INC-YYYY-MMDD-NNNN, NNNN = id padded. */
    private function formatIncidentId(object $row): string
    {
        $started = CarbonImmutable::parse($row->started_at);

        return sprintf('INC-%s-%s-%04d', $started->format('Y'), $started->format('md'), (int) $row->id);
    }

    /** Status derive: resolved_at!=null → resolved; иначе investigating если detected_at есть; иначе open. */
    private function deriveStatus(object $row): string
    {
        if ($row->resolved_at !== null) {
            return 'resolved';
        }
        if ($row->detected_at !== null) {
            return 'investigating';
        }

        return 'open';
    }

    /** PG-array literal '{1,2,3}' → count элементов. */
    private function parsePgArray(string $literal): int
    {
        $trimmed = trim($literal, '{}');
        if ($trimmed === '') {
            return 0;
        }

        return count(explode(',', $trimmed));
    }

    /**
     * Open / investigating / РКН-pending counts для page-head.
     *
     * @return array<string, int>
     */
    private function computeSummary(): array
    {
        $base = DB::table('incidents_log');

        return [
            'open' => (clone $base)->whereNull('resolved_at')->whereNull('detected_at')->count(),
            'investigating' => (clone $base)->whereNull('resolved_at')->whereNotNull('detected_at')->count(),
            'rkn_pending' => (clone $base)
                ->where('type', 'data_breach')
                ->whereNull('rkn_notified_at')
                ->whereNull('resolved_at')
                ->count(),
            'total_unresolved' => (clone $base)->whereNull('resolved_at')->count(),
        ];
    }
}
