<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Concerns\ResolvesAdminUserId;
use App\Http\Controllers\Controller;
use App\Services\Pd\PdErasureService;
use Carbon\CarbonImmutable;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;

/**
 * SaaS-admin: управление обращениями субъектов ПДн (152-ФЗ).
 *
 * Saas-уровневый endpoint (НЕ tenant-aware), под middleware('saas-admin').
 * Production: middleware('auth:saas-admin') — реализуется после Б-1 + DO-4.
 *
 * Маршруты:
 *   GET    /api/admin/pd-subject-requests         → index
 *   POST   /api/admin/pd-subject-requests         → store
 *   GET    /api/admin/pd-subject-requests/{id}    → show
 *   POST   /api/admin/pd-subject-requests/{id}/erase → executeErasure
 */
class AdminPdSubjectRequestsController extends Controller
{
    use ResolvesAdminUserId;

    public function __construct(private readonly PdErasureService $erasureService) {}

    /**
     * GET /api/admin/pd-subject-requests
     *
     * Список обращений с пагинацией. Фильтры: status, request_type.
     */
    public function index(Request $request): JsonResponse
    {
        $status = (string) $request->query('status', '');
        $requestType = (string) $request->query('request_type', '');
        $limit = max(1, min(200, (int) $request->query('limit', '50')));
        $offset = max(0, (int) $request->query('offset', '0'));

        $query = DB::connection('pgsql_supplier')
            ->table('pd_subject_requests')
            ->orderByDesc('received_at')
            ->orderByDesc('id');

        if ($status !== '') {
            $query->where('status', $status);
        }
        if ($requestType !== '') {
            $query->where('request_type', $requestType);
        }

        $total = (clone $query)->count('id');
        $rows = $query->limit($limit)->offset($offset)->get();

        return response()->json([
            'data' => $rows->map(fn ($r) => $this->formatRow($r)),
            'total' => $total,
            'limit' => $limit,
            'offset' => $offset,
        ]);
    }

    /**
     * GET /api/admin/pd-subject-requests/{id}
     */
    public function show(int $id): JsonResponse
    {
        $row = DB::connection('pgsql_supplier')
            ->table('pd_subject_requests')
            ->where('id', $id)
            ->first();

        if ($row === null) {
            return response()->json(['message' => 'Обращение не найдено.'], 404);
        }

        return response()->json(['data' => $this->formatRow($row)]);
    }

    /**
     * POST /api/admin/pd-subject-requests
     *
     * Создать новое обращение субъекта. Deadline автоматически +30 дней
     * через PostgreSQL-триггер trg_pd_subject_requests_deadline.
     */
    public function store(Request $request): JsonResponse
    {
        $validated = $request->validate([
            'subject_email' => ['nullable', 'email', 'max:255'],
            'subject_phone' => ['nullable', 'string', 'max:20'],
            'subject_full_name' => ['nullable', 'string', 'max:255'],
            'request_type' => ['required', Rule::in(['access', 'rectification', 'deletion', 'objection'])],
            'description' => ['nullable', 'string', 'max:4096'],
            'tenant_id' => ['nullable', 'integer', 'min:1'],
        ]);

        // Минимум один идентификатор субъекта
        if (empty($validated['subject_email']) && empty($validated['subject_phone'])) {
            return response()->json([
                'message' => 'Укажите email или телефон субъекта.',
                'errors' => ['subject_email' => ['Необходимо email или телефон.']],
            ], 422);
        }

        $now = CarbonImmutable::now();

        // NB: deadline_at заполняется триггером trg_pd_subject_requests_deadline
        // (received_at + 30 дней). Передаём placeholder — триггер перезапишет.
        $id = DB::connection('pgsql_supplier')
            ->table('pd_subject_requests')
            ->insertGetId([
                'received_at' => $now,
                'subject_email' => $validated['subject_email'] ?? null,
                'subject_phone' => $validated['subject_phone'] ?? null,
                'subject_full_name' => $validated['subject_full_name'] ?? null,
                'request_type' => $validated['request_type'],
                'description' => $validated['description'] ?? null,
                'status' => 'received',
                'tenant_id' => $validated['tenant_id'] ?? null,
                'processing_restricted' => false,
                // deadline_at: trigger перезапишет, но NOT NULL требует значения
                'deadline_at' => $now->addDays(30),
            ]);

        $row = DB::connection('pgsql_supplier')
            ->table('pd_subject_requests')
            ->where('id', $id)
            ->first();

        return response()->json(['data' => $this->formatRow($row)], 201);
    }

    /**
     * POST /api/admin/pd-subject-requests/{id}/erase
     *
     * Выполнить анонимизацию ПДн для обращения с request_type='deletion'.
     * Возвращает counts анонимизированных записей.
     */
    public function executeErasure(int $id, Request $request): JsonResponse
    {
        $row = DB::connection('pgsql_supplier')
            ->table('pd_subject_requests')
            ->where('id', $id)
            ->first();

        if ($row === null) {
            return response()->json(['message' => 'Обращение не найдено.'], 404);
        }

        if ($row->request_type !== 'deletion') {
            return response()->json([
                'message' => 'Анонимизация доступна только для обращений типа "deletion".',
            ], 422);
        }

        if ($row->status === 'completed') {
            return response()->json([
                'message' => 'Обращение уже выполнено.',
            ], 422);
        }

        if (empty($row->subject_email) && empty($row->subject_phone)) {
            return response()->json([
                'message' => 'В обращении не указан email или телефон субъекта.',
            ], 422);
        }

        $adminId = $this->resolveAdminUserId(
            $request,
            'pd-erasure-stub@system.local',
            'PD Erasure System',
        );

        $counts = $this->erasureService->eraseSubject(
            email: $row->subject_email ?: null,
            phone: $row->subject_phone ?: null,
            tenantId: $row->tenant_id !== null ? (int) $row->tenant_id : null,
            actorAdminId: $adminId,
            requestId: (string) $id,
        );

        return response()->json([
            'message' => 'Анонимизация выполнена.',
            'counts' => $counts,
        ]);
    }

    /**
     * Форматировать строку pd_subject_requests в массив для API.
     *
     * @return array<string, mixed>
     */
    private function formatRow(object $row): array
    {
        return [
            'id' => (int) $row->id,
            'received_at' => $row->received_at !== null
                ? CarbonImmutable::parse($row->received_at)->toIso8601String() : null,
            'subject_email' => $row->subject_email,
            'subject_phone' => $row->subject_phone,
            'subject_full_name' => $row->subject_full_name,
            'request_type' => $row->request_type,
            'description' => $row->description,
            'status' => $row->status,
            'tenant_id' => $row->tenant_id !== null ? (int) $row->tenant_id : null,
            'assigned_admin_id' => $row->assigned_admin_id !== null
                ? (int) $row->assigned_admin_id : null,
            'response_text' => $row->response_text,
            'deadline_at' => $row->deadline_at !== null
                ? CarbonImmutable::parse($row->deadline_at)->toIso8601String() : null,
            'completed_at' => $row->completed_at !== null
                ? CarbonImmutable::parse($row->completed_at)->toIso8601String() : null,
            'processing_restricted' => (bool) $row->processing_restricted,
        ];
    }
}
