<?php

namespace App\Http\Controllers;

use App\Exports\SegmentContractsExport;
use App\Http\Requests\ExportSegmentContractsRequest;
use App\Http\Requests\StoreSegmentRequest;
use App\Http\Requests\UpdateSegmentRequest;
use App\Models\Client;
use App\Models\Contract;
use App\Models\Segment;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Inertia\Inertia;
use Maatwebsite\Excel\Facades\Excel;

class SegmentController extends Controller
{
    public function index()
    {
        // Fetch active segments with number of active contracts and total balance sum of those contracts
        // A contract is considered in a segment when the pivot is active=true.
        $segments = Segment::query()
            ->where('active', true)
            ->withCount(['contracts as contracts_count' => function ($q) {
                // On some drivers, wherePivot can compile oddly inside withCount; target the pivot table directly
                $q->where('contract_segment.active', '=', 1);
            }])
            ->get(['id', 'name', 'description']);

        // Compute total balance per segment for active contracts
        $balances = DB::table('segments')
            ->join('contract_segment', 'contract_segment.segment_id', '=', 'segments.id')
            ->join('contracts', 'contracts.id', '=', 'contract_segment.contract_id')
            ->leftJoin('accounts', 'accounts.contract_id', '=', 'contracts.id')
            ->where('segments.active', '=', 1)
            ->where('contract_segment.active', '=', 1)
            ->groupBy('segments.id')
            ->pluck(DB::raw('COALESCE(SUM(accounts.balance_amount),0) as total_balance'), 'segments.id');

        $segments = $segments->map(function ($seg) use ($balances) {
            $seg->total_balance = (string) ($balances[$seg->id] ?? 0);

            return $seg;
        });

        return Inertia::render('Segments/Index', [
            'segments' => $segments,
        ]);
    }

    public function show(Segment $segment)
    {
        $search = request('search');
        $clientFilter = request('client') ?? request('client_id');
        $perPage = request()->integer('perPage', request()->integer('per_page', 15));
        $perPage = max(1, min(200, $perPage));

        $contracts = $this->buildContractsQuery($segment, $search, $clientFilter)
            ->paginate($perPage)
            ->withQueryString();

        $contracts = $this->hydrateClientShortcut($contracts);
        
        // Hide addresses array since we're using the singular address relationship
        $contracts->getCollection()->each(function ($contract) {
            $contract->clientCase?->person?->makeHidden('addresses');
            $contract->clientCase?->client?->person?->makeHidden('addresses');
        });

        $clients = Client::query()
            ->whereHas('clientCases.contracts.segments', function ($q) use ($segment) {
                $q->where('segments.id', $segment->id)
                    ->where('contract_segment.active', '=', 1);
            })
            ->with(['person:id,full_name'])
            ->get(['uuid', 'person_id'])
            ->map(function ($c) {
                return [
                    'uuid' => (string) $c->uuid,
                    'name' => (string) optional($c->person)->full_name,
                ];
            })
            ->sortBy('name', SORT_NATURAL | SORT_FLAG_CASE)
            ->values();

        return Inertia::render('Segments/Show', [
            'segment' => $segment->only(['id', 'name', 'description']),
            'contracts' => $contracts,
            'clients' => $clients,
        ]);
    }

    public function export(ExportSegmentContractsRequest $request, Segment $segment)
    {
        $data = $request->validated();
        $client = $this->resolveClient($data['client'] ?? null);
        $columns = array_values(array_unique($data['columns']));
        $query = $this->buildContractsQuery(
            $segment,
            $data['search'] ?? null,
            $data['client'] ?? null
        );

        if (($data['scope'] ?? ExportSegmentContractsRequest::SCOPE_ALL) === ExportSegmentContractsRequest::SCOPE_CURRENT) {
            $page = max(1, (int) ($data['page'] ?? 1));
            $perPage = max(1, min(200, (int) ($data['per_page'] ?? 15)));
            $query->forPage($page, $perPage);
        }

        $filename = $this->buildExportFilename($segment, $client);

        return Excel::download(new SegmentContractsExport($query, $columns), $filename);
    }

    private function resolveClient(?string $identifier): ?Client
    {
        if (empty($identifier)) {
            return null;
        }

        $query = Client::query()->with(['person:id,full_name']);

        if (Str::isUuid($identifier)) {
            $query->where('uuid', $identifier);
        } elseif (is_numeric($identifier)) {
            $query->where('id', (int) $identifier);
        } else {
            $query->where('uuid', $identifier);
        }

        return $query->first();
    }

    private function buildExportFilename(Segment $segment, ?Client $client): string
    {
        $datePrefix = now()->format('dmy');
        $segmentName = $this->slugify($segment->name ?? 'segment');
        $base = sprintf('%s_%s-Pogodbe', $datePrefix, $segmentName);

        if ($client && $client->person?->full_name) {
            $clientName = $this->slugify($client->person->full_name);

            return sprintf('%s_%s.xlsx', $base, $clientName);
        }

        return sprintf('%s.xlsx', $base);
    }

    private function slugify(string $value): string
    {
        $slug = trim(preg_replace('/[^a-zA-Z0-9]+/', '-', $value), '-');

        return $slug !== '' ? $slug : 'data';
    }

    public function settings(Request $request)
    {
        return Inertia::render('Settings/Segments/Index', [
            'segments' => Segment::query()->get(),
        ]);
    }

    public function store(StoreSegmentRequest $request)
    {
        $data = $request->validated();
        Segment::create([
            'name' => $data['name'],
            'description' => $data['description'] ?? null,
            'active' => $data['active'] ?? true,
        ]);

        return to_route('settings.segments')->with('success', 'Segment created');
    }

    public function update(UpdateSegmentRequest $request, Segment $segment)
    {
        $data = $request->validated();
        $segment->update([
            'name' => $data['name'],
            'description' => $data['description'] ?? null,
            'active' => $data['active'] ?? $segment->active,
            'exclude' => $data['exclude'] ?? $segment->exclude,
        ]);

        return to_route('settings.segments')->with('success', 'Segment updated');
    }

    private function buildContractsQuery(Segment $segment, ?string $search, ?string $clientFilter): Builder
    {
        $query = Contract::query()
            ->whereHas('segments', function ($q) use ($segment) {
                $q->where('segments.id', $segment->id)
                    ->where('contract_segment.active', '=', 1);
            })
            ->with([
                'clientCase.person.address', 
                'type',
                'account',
            ])
            ->latest('id');

        if (! empty($clientFilter)) {
            $query->whereHas('clientCase.client', function ($q) use ($clientFilter) {
                if (is_numeric($clientFilter)) {
                    $q->where('clients.id', (int) $clientFilter);
                } else {
                    $q->where('clients.uuid', $clientFilter);
                }
            });
        }

        if (! empty($search)) {
            $query->where(function ($qq) use ($search) {
                $qq->where('contracts.reference', 'ilike', '%'.$search.'%')
                    ->orWhereHas('clientCase.person', function ($p) use ($search) {
                        $p->where('full_name', 'ilike', '%'.$search.'%');
                    })
                    ->orWhereHas('clientCase.client.person', function ($p) use ($search) {
                        $p->where('full_name', 'ilike', '%'.$search.'%');
                    });
            });
        }

        return $query;
    }

    private function hydrateClientShortcut(LengthAwarePaginator $contracts): LengthAwarePaginator
    {
        $items = collect($contracts->items());
        $items->each(function (Contract $contract) {
            if ($contract->relationLoaded('clientCase') && $contract->clientCase) {
                $contract->setRelation('client', $contract->clientCase->client);
            }
        });

        if (method_exists($contracts, 'setCollection')) {
            $contracts->setCollection($items);
        }

        return $contracts;
    }
}
