<?php

namespace App\Http\Controllers\Api\V2;

use App\Http\Controllers\Controller;
use App\Models\Victim;
use App\Services\Api\ApiClientScopeService;
use App\Services\Api\NgbvdApiStatsService;
use App\Services\Integrations\UbosGbvPortalService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class UbosGbvApiController extends Controller
{
    public function health()
    {
        return response()->json([
            'success' => true,
            'service' => 'NGBVD API',
            'version' => 'v2',
            'data_as_of' => now()->toIso8601String(),
        ]);
    }

    public function referenceData(Request $request)
    {
        $client = $request->attributes->get('api_client');
        $districtIds = $client && method_exists($client, 'districtIdList') && $client->hasDataScope('district') && ! $client->hasDataScope('national') ? $client->districtIdList() : [];
        $districtFilterApplies = $client && ! $client->hasDataScope('national') && ! empty($districtIds);

        return response()->json([
            'success' => true,
            'metadata' => [
                'api_version' => 'v2',
                'data_as_of' => now()->toIso8601String(),
                'api_client_key' => $client ? $client->client_key : null,
//                'data_scope' => $client ? $client->scopeList() : [],
//                'allowed_district_ids' => $districtIds,
            ],
            'data' => [
                'districts' => $this->referenceRows('districts', ['id', 'uuid', 'name'], 'name', null, $districtFilterApplies ? ['id' => $districtIds] : []),
                'sub_counties' => $this->referenceRows('sub_counties', ['id', 'uuid', 'districts_id', 'name'], 'name', null, $districtFilterApplies ? ['districts_id' => $districtIds] : []),
                'parishes' => $this->referenceRows('parishes', [
                    'id', 'uuid', 'districts_id', ['alias' => 'sub_county_id', 'sources' => ['sub_county_id', 'sub_counties_id']], 'name'
                ], 'name', null, $districtFilterApplies ? ['districts_id' => $districtIds] : []),
                'incidents' => $this->referenceRows('incidents', ['id', 'uuid', 'name'], 'name', 'name'),
                'gender' => $this->referenceRows('gender', ['id', 'name']),
                'national_status' => $this->referenceRows('national_status', ['id', 'uuid', 'name']),
                'religion' => $this->referenceRows('religion', ['id', 'uuid', 'name']),
            ],
        ]);
    }

    public function statistics(Request $request, NgbvdApiStatsService $stats)
    {
        $filters = $request->validate([
            'startdate' => ['nullable', 'date'],
            'enddate' => ['nullable', 'date'],
            'district_id' => ['nullable'],
            'incident_id' => ['nullable'],
        ]);

        $client = $request->attributes->get('api_client');

        return response()->json([
            'success' => true,
            'data' => $stats->incidentStatistics($filters, $client),
        ]);
    }

    public function pushToUbos(Request $request, UbosGbvPortalService $service, ApiClientScopeService $scope)
    {
        $validated = $request->validate([
            'victim_uuid' => ['nullable', 'string'],
            'victim_id' => ['nullable'],
        ]);

        $victim = Victim::query()
            ->when(!empty($validated['victim_uuid']), function ($query) use ($validated) {
                return $query->where('uuid', $validated['victim_uuid']);
            })
            ->when(empty($validated['victim_uuid']) && !empty($validated['victim_id']), function ($query) use ($validated) {
                return $query->where('id', $validated['victim_id']);
            })
            ->firstOrFail();

        if ($client = $request->attributes->get('api_client')) {
            $scope->assertCanAccessVictim($client, $victim);
        }

        $log = $service->pushVictim($victim);

        return response()->json([
            'success' => $log->status === 'success',
            'message' => $log->status === 'success' ? 'Record shared with UBOS GBV Portal.' : 'Record sharing failed or is not configured.',
            'log_uuid' => $log->uuid,
            'status' => $log->status,
        ], $log->status === 'success' ? 200 : 422);
    }

    private function referenceRows($table, array $columns, $orderBy = 'name', $whereNotNull = null, array $whereIn = [])
    {
        if (! Schema::hasTable($table)) {
            return collect();
        }

        $select = [];
        foreach ($columns as $column) {
            if (is_string($column)) {
                if (Schema::hasColumn($table, $column)) {
                    $select[] = $column;
                }
                continue;
            }

            if (is_array($column) && isset($column['alias'], $column['sources'])) {
                $source = null;
                foreach ($column['sources'] as $candidate) {
                    if (Schema::hasColumn($table, $candidate)) {
                        $source = $candidate;
                        break;
                    }
                }
                $alias = $this->quoteIdentifier($column['alias']);
                $select[] = $source ? DB::raw($this->quoteIdentifier($source).' as '.$alias) : DB::raw('NULL as '.$alias);
            }
        }

        if (empty($select)) {
            return collect();
        }

        $query = DB::table($table)->select($select);
        if ($whereNotNull && Schema::hasColumn($table, $whereNotNull)) {
            $query->whereNotNull($whereNotNull);
        }
        foreach ($whereIn as $column => $values) {
            if (Schema::hasColumn($table, $column)) {
                $query->whereIn($column, $values);
            }
        }
        if ($orderBy && Schema::hasColumn($table, $orderBy)) {
            $query->orderBy($orderBy);
        }

        return $query->get();
    }

    private function quoteIdentifier($identifier)
    {
        return '`'.str_replace('`', '``', $identifier).'`';
    }
}
