<?php

namespace App\Services;

use App\Models\ClientCase;
use App\Models\Contract;
use App\Models\Document;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;

class ClientCaseDataService
{
    /**
     * Get contracts for a client case with optional segment filtering.
     */
    public function getContracts(ClientCase $clientCase, ?int $segmentId = null): Collection
    {
        $query = $clientCase->contracts()
            ->select(['id', 'uuid', 'reference', 'start_date', 'end_date', 'description', 'meta', 'active', 'type_id', 'client_case_id', 'created_at'])
            ->with([
                'type:id,name',
                'account' => function ($q) {
                    $q->select([
                        'accounts.id',
                        'accounts.contract_id',
                        'accounts.type_id',
                        'accounts.initial_amount',
                        'accounts.balance_amount',
                        'accounts.promise_date',
                        'accounts.created_at',
                        'accounts.updated_at',
                    ])->orderByDesc('accounts.id');
                },
                'segments:id,name',
                'objects:id,contract_id,reference,name,description,type,created_at',
            ])
            ->orderByDesc('created_at');

        if (! empty($segmentId)) {
            $query->forSegment($segmentId);
        }

        return $query->get();
    }

    /**
     * Get paginated activities for a client case with optional segment and filter constraints.
     */
    public function getActivities(
        ClientCase $clientCase,
        ?int $segmentId = null,
        ?string $encodedFilters = null,
        array $contractIds = [],
        int $perPage = 20
    ): LengthAwarePaginator {
        $query = $clientCase->activities()
            ->with(['action', 'decision', 'contract:id,uuid,reference', 'user:id,name', 'emailLogs:id'])
            ->orderByDesc('created_at');

        if (! empty($segmentId)) {
            $query->forSegment($segmentId, $contractIds);
        }

        if (! empty($encodedFilters)) {
            $query->withFilters($encodedFilters, $clientCase);
        }

        $perPage = max(1, min(100, $perPage));

        return $query->paginate($perPage, ['*'], 'activities_page')->withQueryString();
    }

    /**
     * Get merged documents from case and its contracts.
     */
    public function getDocuments(ClientCase $clientCase, array $contractIds = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = null;
        $caseDocsQuery = Document::query()
            ->select([
                'documents.id',
                'documents.uuid',
                'documents.documentable_id',
                'documents.documentable_type',
                'documents.name',
                'documents.file_name',
                'documents.original_name',
                'documents.extension',
                'documents.mime_type',
                'documents.size',
                'documents.created_at',
                'documents.is_public',
                \DB::raw('NULL as contract_reference'),
                \DB::raw('NULL as contract_uuid'),
                \DB::raw("'{$clientCase->uuid}' as client_case_uuid"),
                \DB::raw('users.name as created_by'),
            ])
            ->join('users', 'documents.user_id', '=', 'users.id')
            ->where('documents.documentable_type', ClientCase::class)
            ->where('documents.documentable_id', $clientCase->id);

        if (! empty($contractIds)) {
            // Get contract references for mapping
            $contracts = Contract::query()
                ->whereIn('id', $contractIds)
                ->get(['id', 'uuid', 'reference'])
                ->keyBy('id');

            $contractDocsQuery = Document::query()
                ->select([
                    'documents.id',
                    'documents.uuid',
                    'documents.documentable_id',
                    'documents.documentable_type',
                    'documents.name',
                    'documents.file_name',
                    'documents.original_name',
                    'documents.extension',
                    'documents.mime_type',
                    'documents.size',
                    'documents.created_at',
                    'documents.is_public',
                    'contracts.reference as contract_reference',
                    'contracts.uuid as contract_uuid',
                    \DB::raw('NULL as client_case_uuid'),
                    \DB::raw('users.name as created_by'),
                ])
                ->join('users', 'documents.user_id', '=', 'users.id')
                ->join('contracts', 'documents.documentable_id', '=', 'contracts.id')
                ->where('documents.documentable_type', Contract::class)
                ->whereIn('documents.documentable_id', $contractIds);

            // Union the queries
            $query = $caseDocsQuery->union($contractDocsQuery);
        } else {
            $query = $caseDocsQuery;
        }

        return \DB::table(\DB::raw("({$query->toSql()}) as documents"))
            ->mergeBindings($query->getQuery())
            ->orderByDesc('created_at')
            ->paginate($perPage, ['*'], 'documentsPage')
            ->withQueryString();
    }

    /**
     * Get archive metadata from latest non-reactivate archive setting.
     */
    public function getArchiveMeta(): array
    {
        $latestArchiveSetting = \App\Models\ArchiveSetting::query()
            ->where('enabled', true)
            ->where(function ($q) {
                $q->whereNull('reactivate')->orWhere('reactivate', false);
            })
            ->orderByDesc('id')
            ->first();

        $archiveSegmentId = optional($latestArchiveSetting)->segment_id;
        $relatedArchiveTables = [];

        if ($latestArchiveSetting) {
            $entities = (array) $latestArchiveSetting->entities;
            foreach ($entities as $edef) {
                if (isset($edef['related']) && is_array($edef['related'])) {
                    foreach ($edef['related'] as $rel) {
                        $relatedArchiveTables[] = $rel;
                    }
                }
            }
            $relatedArchiveTables = array_values(array_unique($relatedArchiveTables));
        }

        return [
            'archive_segment_id' => $archiveSegmentId,
            'related_tables' => $relatedArchiveTables,
        ];
    }
}
