<?php

namespace App\Services\DataEntry;

use App\Models\AgeGroup;
use App\Models\Authority;
use App\Models\CaseStatus;
use App\Models\District;
use App\Models\EducationLevel;
use App\Models\IdType;
use App\Models\Incident;
use App\Models\MaritalStatus;
use App\Models\NationalStatus;
use App\Models\NationalStatusCategory;
use App\Models\Nationality;
use App\Models\Ocupation;
use App\Models\Parish;
use App\Models\Place;
use App\Models\Relation;
use App\Models\Religion;
use App\Models\Service;
use App\Models\Status;
use App\Models\SubCounty;
use App\Models\TimeofDay;
use App\Models\Victim;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\DB;

class ReferenceDataService
{
    public function forDataEntry(?Authenticatable $user): array
    {
        [$districts, $subcounties, $parishes] = $this->locationsForUser($user);

        return [
            'times' => TimeofDay::where('status', '1')->get(),
            'relations' => Relation::where('status', '1')->get(),
            'districts' => $districts,
            'subcounties' => $subcounties,
            'parishes' => $parishes,
            'religions' => Religion::where('status', '1')->get(),
            'agegroups' => AgeGroup::where('status', '1')->get(),
            'mariage' => MaritalStatus::where('status', '1')->orderBy('name')->get(),
            'nationality' => Nationality::select('id', 'name')->orderBy('id')->get(),
            'status' => NationalStatus::where('status', '1')->get(),
            'incidents' => Incident::orderBy('name')->get(),
            'agegroup' => AgeGroup::where('status', '1')->get(),
            'services' => Service::where('status', '1')->get(),
            'authorities' => Authority::orderBy('name')->get(),
            'statuses' => CaseStatus::orderBy('name')->get(),
            'education' => EducationLevel::where('status', '1')->get(),
            'occupation' => Ocupation::where('status', '1')->get(),
            'places' => Place::orderBy('name')->get(),
            'idtypes' => IdType::where('status', '1')->get(),
            'nstatuscategories' => NationalStatusCategory::where('status', '1')->get(),
        ];
    }

    public function forUpdate(?Authenticatable $user, string $victimId): array
    {
        $data = $this->forDataEntry($user);
        $data['survivor'] = Victim::findOrFail($victimId);
        $data['pendingPoints'] = Status::select('id', 'name')->orderBy('name')->get();

        return $data;
    }

    public function caseList(?Authenticatable $user, ?string $startDate, ?string $endDate, int $perPage = 10): array
    {
        $startDate = $startDate ? date('Y-m-d', strtotime($startDate)) : date('Y-01-01');
        $endDate = $endDate ? date('Y-m-d', strtotime($endDate)) : date('Y-m-d');
        $perPage = max(10, min($perPage, 5000));

        $districts = $this->districtIdsForUser($user);

        $query = DB::table('victim')
            ->select(
                'victim.*',
                'gender.name as genderValue',
                'nationality.name as nationality',
                'national_status.name as national_status',
                'district.name as district',
                'subbcounty.name as subbcounty',
                'parish.name as parish',
                'users.name as created_by',
                'users.email as email',
                'user_roles.name as urole'
            )
            ->leftJoin('gender', 'victim.gender', '=', 'gender.id')
            ->leftJoin('national_status as national_status', 'victim.nationality_status', '=', 'national_status.id')
            ->leftJoin('nationality as nationality', 'victim.nationality', '=', 'nationality.id')
            ->leftJoin('districts as district', 'victim.districtid', '=', 'district.id')
            ->leftJoin('sub_counties as subbcounty', 'victim.subcountyid', '=', 'subbcounty.id')
            ->leftJoin('parishes as parish', 'victim.parishid', '=', 'parish.id')
            ->leftJoin('users', 'victim.created_by', '=', 'users.id')
            ->leftJoin('user_roles', 'users.userrole', '=', 'user_roles.id')
            ->whereBetween('interview_date', [$startDate, $endDate]);

        if ($districts !== null) {
            $query->whereIn('victim.districtid', $districts);
        }

        $victims = $query->paginate($perPage)->onEachSide(5);
        $totalCount = $districts === null ? Victim::count() : Victim::whereIn('districtid', $districts)->count();

        return [
            'victims' => $victims,
            'perPage' => $perPage,
            'availablePerPageOptions' => $this->perPageOptions((int) $totalCount),
        ];
    }

    private function locationsForUser(?Authenticatable $user): array
    {
        $districtIds = $this->districtIdsForUser($user);

        if ($districtIds === null) {
            return [
                District::select('id', 'name')->orderBy('name')->get(),
                SubCounty::select('id', 'name')->orderBy('name')->get(),
                Parish::select('id', 'name')->orderBy('name')->get(),
            ];
        }

        return [
            District::select('id', 'name')->whereIn('id', $districtIds)->orderBy('name')->get(),
            SubCounty::select('id', 'name')->whereIn('districts_id', $districtIds)->orderBy('name')->get(),
            Parish::select('id', 'name')->whereIn('districts_id', $districtIds)->orderBy('name')->get(),
        ];
    }

    private function districtIdsForUser(?Authenticatable $user): ?array
    {
        $districts = trim((string) optional($user)->district);

        if ($districts === '' || $districts === '*') {
            return null;
        }

        return array_values(array_filter(array_map('trim', explode(',', $districts))));
    }

    private function perPageOptions(int $total): array
    {
        $options = [10, 25, 50];
        foreach ([100, 200, 500, 1000, 5000] as $option) {
            if ($total > $option / 2) {
                $options[] = $option;
            }
        }

        return array_values(array_unique($options));
    }
}
