<?php

namespace App\Services\Integrations;

use App\Models\IntegrationLog;
use App\Models\Victim;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Schema;

class NsrRegistryService
{
    private $logs;

    public function __construct(IntegrationLogService $logs)
    {
        $this->logs = $logs;
    }

    /**
     * Build a granular NSR payload. The payload deliberately separates survivor, incident,
     * perpetrator, witness, service/action and case-status records so NSR can ingest either
     * the full case or single record changes in near real-time.
     */
    public function buildPayload(Victim $victim, string $recordType = 'case'): array
    {
        $victim->load(['incidents', 'perpetrators', 'witnesses', 'actions', 'statuses']);

        return [
            'api_version' => config('ngbvd_integrations.nsr.api_version', 'v1'),
            'source_system' => 'NGBVD',
            'target_system' => 'NSR',
            'event_type' => $recordType,
            'event_uuid' => (string) \Illuminate\Support\Str::uuid(),
            'event_time' => now()->toIso8601String(),
            'case' => [
                'uuid' => $this->publicUuid($victim),
                'reference_id' => $this->publicUuid($victim) ?: (string) $victim->id,
                'crb_number' => $victim->crb_number,
                'survivor_code' => $victim->survivor_code,
                'interview_date' => $victim->interview_date,
                'interview_time' => $victim->interview_time,
                'district_id' => $victim->districtid,
                'subcounty_id' => $victim->subcountyid,
                'parish_id' => $victim->parishid,
                'village' => $victim->village,
                'created_at' => optional($victim->created_at)->toDateTimeString(),
                'updated_at' => optional($victim->updated_at)->toDateTimeString(),
            ],
            'survivor' => [
                'uuid' => $this->publicUuid($victim),
                'gender_id' => $victim->gender,
                'nationality_id' => $victim->nationality,
                'national_id_type_id' => $victim->idtype ?? null,
                'national_id_number' => $this->maskIdentifier($victim->id_number ?? null),
                'age_or_dob' => $victim->dob,
                'nationality_status_id' => $victim->nationality_status,
                'nationality_status_category_id' => $victim->nationality_status_category_id ?? null,
                'religion_id' => $victim->religion,
                'marital_status_id' => $victim->marital_status,
                'number_of_children' => $victim->number_of_children,
                'pwd' => $victim->pwd,
                'education_id' => $victim->education,
                'occupation_id' => $victim->occupation,
                'employment_status_id' => $victim->employment_status_id ?? null,
                'previous_reporting' => $victim->previos_reporting,
            ],
            'incidents' => $victim->incidents->map(function ($incident) {
                return [
                    'uuid' => $this->publicUuid($incident),
                    'incident_type_id' => $incident->incidentid,
                    'incident_date' => $incident->incident_date,
                    'incident_time_id' => $incident->incident_time,
                    'reported_by_id' => $incident->reported_by,
                    'district_id' => $incident->districtid,
                    'subcounty_id' => $incident->subcountyid,
                    'parish_id' => $incident->parishid,
                    'village' => $incident->village,
                    'notes_present' => !empty($incident->notes),
                    'created_at' => optional($incident->created_at)->toDateTimeString(),
                    'updated_at' => optional($incident->updated_at)->toDateTimeString(),
                ];
            })->values()->all(),
            'perpetrators' => $victim->perpetrators->map(function ($row) {
                return [
                    'uuid' => $this->publicUuid($row),
                    'gender_id' => $row->gender,
                    'age_group_id' => $row->agegroup,
                    'relation_id' => $row->relation,
                    'nationality_id' => $row->nationality,
                    'nationality_status_id' => $row->national_status,
                    'education_id' => $row->education,
                    'occupation_id' => $row->occupation,
                    'threat' => $row->threat,
                    'phone_present' => !empty($row->phone),
                ];
            })->values()->all(),
            'witnesses' => $victim->witnesses->map(function ($row) {
                return [
                    'uuid' => $this->publicUuid($row),
                    'name_present' => !empty($row->name),
                    'gender_id' => $row->gender,
                    'age_group_id' => $row->agegroup,
                    'relation_id' => $row->relation,
                ];
            })->values()->all(),
            'service_actions' => $victim->actions->map(function ($row) {
                return [
                    'uuid' => $this->publicUuid($row),
                    'reported_to_id' => $row->reported_to,
                    'referred_to_id' => $row->refferedto,
                    'report_date' => $row->report_date,
                    'date_referred' => $row->date_reffered,
                    'service_ids' => $row->services,
                    'notes_present' => !empty($row->notes),
                ];
            })->values()->all(),
            'case_statuses' => $victim->statuses->map(function ($row) {
                return [
                    'uuid' => $this->publicUuid($row),
                    'status_id' => $row->incident_status,
                    'date_logged' => $row->date_logged,
                    'pending_point_id' => $row->pendingpoint,
                    'details_present' => !empty($row->details),
                ];
            })->values()->all(),
            'privacy' => [
                'classification' => 'sensitive_gbv_case_data',
                'data_minimisation' => true,
                'direct_identifiers_masked' => true,
                'requires_approved_data_sharing_protocol' => true,
            ],
        ];
    }

    public function pushVictim(Victim $victim, string $recordType = 'case'): IntegrationLog
    {
        $payload = $this->buildPayload($victim, $recordType);
        $endpoint = rtrim((string) config('ngbvd_integrations.nsr.base_url'), '/') . '/' . ltrim((string) config('ngbvd_integrations.nsr.push_endpoint', '/api/v1/ngbvd/cases'), '/');

        $log = $this->logs->start([
            'integration_name' => 'NSR',
            'system_name' => 'National Single Registry',
            'direction' => 'outbound',
            'endpoint' => $endpoint,
            'http_method' => 'POST',
            'record_type' => $recordType,
            'record_id' => $victim->id,
            'record_uuid' => $this->publicUuid($victim),
            'case_reference' => $victim->crb_number ?: $victim->survivor_code,
            'request_payload_hash' => $this->logs->hashPayload($payload),
            'request_payload_preview' => $payload,
            'triggered_by' => Auth::id(),
        ]);

        if (!config('ngbvd_integrations.nsr.enabled') || empty(config('ngbvd_integrations.nsr.base_url'))) {
            return $this->logs->failure($log, 'NSR integration is not enabled or NSR base URL is not configured.');
        }

        try {
            $request = Http::timeout((int) config('ngbvd_integrations.nsr.timeout', 30))
                ->withOptions(['verify' => (bool) config('ngbvd_integrations.nsr.verify_ssl', true)])
                ->acceptJson();

            if ($token = config('ngbvd_integrations.nsr.bearer_token')) {
                $request = $request->withToken($token);
            }

            if ($clientId = config('ngbvd_integrations.nsr.client_id')) {
                $request = $request->withHeaders(['X-NGBVD-Client-Id' => $clientId]);
            }

            $response = $request->post($endpoint, $payload);

            if ($response->successful()) {
                return $this->logs->success($log, $response->status(), $response->body());
            }

            return $this->logs->failure($log, 'NSR returned a non-success response.', $response->status(), $response->body());
        } catch (\Throwable $e) {
            return $this->logs->failure($log, $e->getMessage());
        }
    }

    private function publicUuid($model): ?string
    {
        return $model && Schema::hasColumn($model->getTable(), 'uuid') ? ($model->uuid ?: null) : null;
    }

    private function maskIdentifier(?string $value): ?string
    {
        if (!$value) {
            return null;
        }

        $length = strlen($value);
        if ($length <= 4) {
            return str_repeat('*', $length);
        }

        return str_repeat('*', $length - 4) . substr($value, -4);
    }
}
