<?php

namespace App\Libs\Services;

use App\Models\MapItem;
use App\Libs\Database\Eloquent\Collection\ContentTypeCollection;
use App\Models\MapInformation;

class MapItemService
{
    public function list(): ?ContentTypeCollection
    {
        $mapItems = MapItem::full()
            ->where('status', 'published')
            ->get();

        return $mapItems;
    }

    public function findByMapItemId($data): ?MapItem
    {
        $query = MapItem::full()
            ->where('status', 'published')
            ->where('id', $data['countryId']);

        $query->with([
            'mapInformation' => function ($query) use ($data) {
                $query->full()
                    ->where('status', 'published')
                    ->where('counterparty_type', $data['counterpartyType'])
                    ->where('settlement_type', $data['settlementType'])
                    ->where('relevant_commodity', $data['relevantCommodity']);
            },
        ]);

        return $query->first();
    }

    public function findByMapItemIdWithAllMapInformation($mapItemId): ?MapItem
    {
        $query = MapItem::full()
            ->where('status', 'published')
            ->where('id', $mapItemId);

        $query->with([
            'mapInformations' => function ($query) {
                $query->full()
                    ->where('status', 'published')
                    ->orderBy('counterparty_type')
                    ->orderBy('settlement_type')
                    ->orderBy('relevant_commodity');
            },
        ]);

        return $query->first();
    }

    public function getMapInfoFilters($data)
    {
        // Check if the countryId is valid (exists and is published)
        $validCountry = true;
        if (isset($data['countryId']) && is_numeric($data['countryId'])) {
            $countryExists = MapItem::full()
                ->where('status', 'published')
                ->where('id', $data['countryId'])
                ->exists();

            if (!$countryExists) {
                $validCountry = false;
                // Clear other filters since we're going to return empty lists for them
                $data['counterpartyType'] = null;
                $data['settlementType'] = null;
                $data['relevantCommodity'] = null;
            }
        }

        // Prepare the result array
        $availableFilters = [
            'countries' => [],
            'counterpartyTypes' => [],
            'settlementTypes' => [],
            'relevantCommodities' => []
        ];

        // Start with a base query for published map information records
        $query = MapInformation::full()->where('status', 'published');

        // Check if any filter is applied
        $hasFilters = !empty($data['counterpartyType']) || !empty($data['settlementType']) || !empty($data['relevantCommodity']);

        // Apply filters based on the data provided (for filtering other options)
        $filteredQuery = clone $query;

        if (!empty($data['countryId'])) {
            $filteredQuery->where('map_item_id', $data['countryId']);
        }

        if (!empty($data['counterpartyType'])) {
            $filteredQuery->where('counterparty_type', $data['counterpartyType']);
        }

        if (!empty($data['settlementType'])) {
            $filteredQuery->where('settlement_type', $data['settlementType']);
        }

        if (!empty($data['relevantCommodity'])) {
            $filteredQuery->where('relevant_commodity', $data['relevantCommodity']);
        }

        // ----------------------- Handle Countries -----------------------
        // Always get all countries regardless of filters
        $countries = MapItem::full()
            ->where('status', 'published')
            ->get(['id', 'title'])
            ->map(function ($item) {
                return [
                    'id' => $item->id,
                    'name' => $item->title
                ];
            })
            ->toArray();

        // If a country is selected, make sure it appears first in the list
        if (!empty($data['countryId'])) {
            $selectedCountryIndex = -1;
            foreach ($countries as $index => $country) {
                if ($country['id'] == $data['countryId']) {
                    $selectedCountryIndex = $index;
                    break;
                }
            }

            // If found, move it to the top
            if ($selectedCountryIndex >= 0) {
                $selectedCountry = $countries[$selectedCountryIndex];
                unset($countries[$selectedCountryIndex]);
                array_unshift($countries, $selectedCountry);
                $countries = array_values($countries); // Reindex array
            }
        }

        $availableFilters['countries'] = $countries;

        // ----------------------- Handle Counterparty Types -----------------------
        // If the country is not valid, return empty counterparty types
        if (!$validCountry) {
            $availableFilters['counterpartyTypes'] = [];
        } else {
            // Get counterparty types
            $counterpartyTypeQuery = clone $query;

            // Apply all filters except counterpartyType
            if (!empty($data['countryId'])) {
                $counterpartyTypeQuery->where('map_item_id', $data['countryId']);
            }

            if (!empty($data['settlementType'])) {
                $counterpartyTypeQuery->where('settlement_type', $data['settlementType']);
            }

            if (!empty($data['relevantCommodity'])) {
                $counterpartyTypeQuery->where('relevant_commodity', $data['relevantCommodity']);
            }

            // Get available counterparty types
            $counterpartyTypes = $counterpartyTypeQuery->pluck('counterparty_type')->unique()->toArray();
            $formattedCounterpartyTypes = array_values(array_map(function ($type) {
                return [
                    'id' => $type,
                    'name' => $this->formatCounterpartyTypeName($type)
                ];
            }, $counterpartyTypes));

            // If a counterparty type is selected, ensure it's in the list
            if (!empty($data['counterpartyType'])) {
                $hasSelectedType = false;
                foreach ($formattedCounterpartyTypes as $type) {
                    if ($type['id'] === $data['counterpartyType']) {
                        $hasSelectedType = true;
                        break;
                    }
                }

                if (!$hasSelectedType) {
                    array_unshift($formattedCounterpartyTypes, [
                        'id' => $data['counterpartyType'],
                        'name' => $this->formatCounterpartyTypeName($data['counterpartyType'])
                    ]);
                }
            }

            $availableFilters['counterpartyTypes'] = $formattedCounterpartyTypes;
        }

        // ----------------------- Handle Settlement Types -----------------------
        // If the country is not valid, return empty settlement types
        if (!$validCountry) {
            $availableFilters['settlementTypes'] = [];
        } else {
            // Get settlement types
            $settlementTypeQuery = clone $query;

            // Apply all filters except settlementType
            if (!empty($data['countryId'])) {
                $settlementTypeQuery->where('map_item_id', $data['countryId']);
            }

            if (!empty($data['counterpartyType'])) {
                $settlementTypeQuery->where('counterparty_type', $data['counterpartyType']);
            }

            if (!empty($data['relevantCommodity'])) {
                $settlementTypeQuery->where('relevant_commodity', $data['relevantCommodity']);
            }

            // Get available settlement types
            $settlementTypes = $settlementTypeQuery->pluck('settlement_type')->unique()->toArray();
            $formattedSettlementTypes = array_values(array_map(function ($type) {
                return [
                    'id' => $type,
                    'name' => ucfirst($type)
                ];
            }, $settlementTypes));

            // If a settlement type is selected, ensure it's in the list
            if (!empty($data['settlementType'])) {
                $hasSelectedType = false;
                foreach ($formattedSettlementTypes as $type) {
                    if ($type['id'] === $data['settlementType']) {
                        $hasSelectedType = true;
                        break;
                    }
                }

                if (!$hasSelectedType) {
                    array_unshift($formattedSettlementTypes, [
                        'id' => $data['settlementType'],
                        'name' => ucfirst($data['settlementType'])
                    ]);
                }
            }

            $availableFilters['settlementTypes'] = $formattedSettlementTypes;
        }

        // ----------------------- Handle Relevant Commodities -----------------------
        // If the country is not valid, return empty relevant commodities
        if (!$validCountry) {
            $availableFilters['relevantCommodities'] = [];
        } else {
            // Get relevant commodities
            $commodityQuery = clone $query;

            // Apply all filters except relevantCommodity
            if (!empty($data['countryId'])) {
                $commodityQuery->where('map_item_id', $data['countryId']);
            }

            if (!empty($data['counterpartyType'])) {
                $commodityQuery->where('counterparty_type', $data['counterpartyType']);
            }

            if (!empty($data['settlementType'])) {
                $commodityQuery->where('settlement_type', $data['settlementType']);
            }

            // Get available commodities
            $relevantCommodities = $commodityQuery->pluck('relevant_commodity')->unique()->toArray();

            $nameMap = [
                'power_gas' => 'Power/Gas',
                'co2_allowances' => 'CO2 Allowances',
                'green_certificates' => 'Green Certificates',
                'mixed_portfolio' => 'Mixed Portfolio'
            ];

            $formattedCommodities = array_values(array_map(function ($commodity) use ($nameMap) {
                return [
                    'id' => $commodity,
                    'name' => $nameMap[$commodity] ?? ucfirst(str_replace('_', '/', $commodity))
                ];
            }, $relevantCommodities));

            // If a commodity is selected, ensure it's in the list
            if (!empty($data['relevantCommodity'])) {
                $hasSelectedCommodity = false;
                foreach ($formattedCommodities as $commodity) {
                    if ($commodity['id'] === $data['relevantCommodity']) {
                        $hasSelectedCommodity = true;
                        break;
                    }
                }

                if (!$hasSelectedCommodity) {
                    array_unshift($formattedCommodities, [
                        'id' => $data['relevantCommodity'],
                        'name' => $nameMap[$data['relevantCommodity']] ?? ucfirst(str_replace('_', '/', $data['relevantCommodity']))
                    ]);
                }
            }

            $availableFilters['relevantCommodities'] = $formattedCommodities;
        }

        // Sort filters in the specified order
        $availableFilters['counterpartyTypes'] = $this->sortCounterpartyTypes($availableFilters['counterpartyTypes']);
        $availableFilters['settlementTypes'] = $this->sortSettlementTypes($availableFilters['settlementTypes']);
        $availableFilters['relevantCommodities'] = $this->sortRelevantCommodities($availableFilters['relevantCommodities']);

        return $availableFilters;
    }

    /**
     * Format counterparty type name for display
     *
     * @param string $type
     * @return string
     */
    private function formatCounterpartyTypeName($type)
    {
        // Split by underscore and capitalize each part
        $parts = explode('_', $type);
        $formattedParts = array_map('ucfirst', $parts);

        // Join with " - " separator
        return implode(' - ', $formattedParts);
    }

    /**
     * Sort counterparty types in the specified order:
     * Corporate - Corporate, Bank - Corporate, Bank - Bank
     *
     * @param array $counterpartyTypes
     * @return array
     */
    private function sortCounterpartyTypes(array $counterpartyTypes): array
    {
        $order = [
            'corporate_corporate' => 0,
            'bank_corporate' => 1,
            'bank_bank' => 2,
        ];

        usort($counterpartyTypes, function ($a, $b) use ($order) {
            $orderA = $order[$a['id']] ?? 999;
            $orderB = $order[$b['id']] ?? 999;
            return $orderA <=> $orderB;
        });

        return $counterpartyTypes;
    }

    /**
     * Sort settlement types in the specified order:
     * Physical, Financial
     *
     * @param array $settlementTypes
     * @return array
     */
    private function sortSettlementTypes(array $settlementTypes): array
    {
        $order = [
            'physical' => 0,
            'financial' => 1,
        ];

        usort($settlementTypes, function ($a, $b) use ($order) {
            $orderA = $order[$a['id']] ?? 999;
            $orderB = $order[$b['id']] ?? 999;
            return $orderA <=> $orderB;
        });

        return $settlementTypes;
    }

    /**
     * Sort relevant commodities in the specified order:
     * Power/Gas, CO2 Allowances, Green Certificates, Mixed Portfolio
     *
     * @param array $commodities
     * @return array
     */
    private function sortRelevantCommodities(array $commodities): array
    {
        $order = [
            'power_gas' => 0,
            'co2_allowances' => 1,
            'green_certificates' => 2,
            'mixed_portfolio' => 3,
        ];

        usort($commodities, function ($a, $b) use ($order) {
            $orderA = $order[$a['id']] ?? 999;
            $orderB = $order[$b['id']] ?? 999;
            return $orderA <=> $orderB;
        });

        return $commodities;
    }
}
