<?php

namespace App\Http\Controllers\Cartograhie\ChartsData;

use App\Http\Controllers\Cartograhie\Filters\FilterController;
use APPLICATION;
use CARTOGRAPHIE;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;

class ChartsDataController
{
    /**
     * @var FilterController
     */
    private $filter;

    /**
     * Constructeur de la classe ChartsDataController.
     * Initialise le service de filtre.
     *
     * @param FilterController $filterController Le service de filtre à utiliser.
     */
    public function __construct(FilterController $filterController)
    {
        $this->filter = $filterController;
    }

    /**
     * Récupère les achats par domaine en fonction du montant.
     *
     * @return array Un tableau contenant les achats par domaine.
     */
    public function retrieveDomainsPurchaseByAmount(): array
    {
        $query = $this->CreateBaseRequest()->select(CARTOGRAPHIE::DOMAINE, DB::raw('SUM(`montant_ht`) as montant_ht'));
        $this->whereStructureID($query);

        if ($this->filter->getFilters(request())) {
            $query = $this->filter->applyFilters($query, request());
        }

        return $query->groupBy(CARTOGRAPHIE::DOMAINE)
            ->get()
            ->map(function ($item) {
                return [
                    CARTOGRAPHIE::DOMAINE => $item->domaine,
                    CARTOGRAPHIE::MONTANT_HT_LOWER => $item->montant_ht,
                ];
            })
            ->toArray();
    }

    /**
     * Récupère le taux de couverture.
     *
     * @return array Un tableau contenant le taux de couverture.
     */
    public function retrieveCoverageRate(): array
    {
        $inMarket = $this->CreateBaseRequest()
            ->select(DB::raw('SUM(`montant_ht`) as montant_ht'));
        $this->whereStructureID($inMarket);
        if ($this->filter->getFilters(request())) {
            $inMarket = $this->filter->applyFilters($inMarket, request());
        }
        $inMarket = $inMarket->where(CARTOGRAPHIE::LIBELLE_MARCHE, '!=', 'HORS MARCHE')
            ->get()
            ->toArray();

        $offMarket = $this->CreateBaseRequest()
            ->select(DB::raw('SUM(`montant_ht`) as montant_ht'));
        $this->whereStructureID($offMarket);
        if ($this->filter->getFilters(request())) {
            $offMarket = $this->filter->applyFilters($offMarket, request());
        }
        $offMarket = $offMarket->where(CARTOGRAPHIE::LIBELLE_MARCHE, '=', 'HORS MARCHE')
            ->get()
            ->toArray();

        return [
            'inMarket' => $inMarket,
            'offMarket' => $offMarket
        ];
    }

    /**
     * Récupère tous les achats par domaine.
     *
     * @return array Un tableau contenant tous les achats par domaine.
     */
    public function retrieveAllDomainsPurchase(): array
    {
        $query = $this->CreateBaseRequest()
            ->select(CARTOGRAPHIE::DOMAINE, DB::raw('SUM(`montant_ht`) as montant_ht'));
        $this->whereStructureID($query);

        if ($this->filter->getFilters(request())) {
            $query = $this->filter->applyFilters($query, request());
        }

        return $query->groupBy(CARTOGRAPHIE::DOMAINE)
            ->get()
            ->map(function ($item) {
                return [
                    CARTOGRAPHIE::DOMAINE => $item->domaine,
                    CARTOGRAPHIE::MONTANT_HT_LOWER => $item->montant_ht,
                ];
            })
            ->toArray();
    }

    /**
     * Récupère le top dix des fournisseurs.
     *
     * @return array Un tableau contenant le top dix des fournisseurs.
     */
    public function retrieveTopTenSuppliers(): array
    {
        $query = $this->CreateBaseRequest()
            ->select(CARTOGRAPHIE::TIERS_NOM, DB::raw('SUM(`montant_ht`) as montant_ht'));
        $this->whereStructureID($query);

        if ($this->filter->getFilters(request())) {
            $query = $this->filter->applyFilters($query, request());
        }

        return $query->groupBy(CARTOGRAPHIE::TIERS_NOM)
            ->take(10)
            ->get()
            ->map(function ($item) {
                return [
                    CARTOGRAPHIE::TIERS_NOM => $item->tiers_nom,
                    CARTOGRAPHIE::MONTANT_HT_LOWER => $item->montant_ht,
                ];
            })
            ->toArray();
    }

    /**
     * Récupère les fournisseurs hors marché par domaine.
     *
     * @return array Un tableau contenant les fournisseurs hors marché par domaine.
     */
    public function retrieveSuppliersOffMarketByDomain(): array
    {
        $page = request()->input('retrieveSuppliersOffMarketByDomain', 1);
        $sortField = request()->input('sort_by', CARTOGRAPHIE::TIERS_NOM);
        $sortOrder = request()->input('sort_order', 'asc');

        $allowedSortFields = [CARTOGRAPHIE::TIERS_NOM, CARTOGRAPHIE::SEGMENT, CARTOGRAPHIE::MONTANT_HT_LOWER];
        if (!in_array($sortField, $allowedSortFields)) {
            $sortField = CARTOGRAPHIE::TIERS_NOM;
        }

        $query = $this->CreateBaseRequest()
            ->select(CARTOGRAPHIE::TIERS_NOM, DB::raw('SUM(montant_ht) as montant_ht'), DB::raw('MAX(segment) as segment'))
            ->where(CARTOGRAPHIE::LIBELLE_MARCHE, '=', 'HORS MARCHE');
        $this->whereStructureID($query);
        $query->groupBy(CARTOGRAPHIE::TIERS_NOM)
            ->orderBy($sortField, $sortOrder);

        $allData = $this->CreateBaseRequest()
            ->select(CARTOGRAPHIE::TIERS_NOM, DB::raw('MAX(segment) as segment'), DB::raw('SUM(montant_ht) as montant_ht'))
            ->where(CARTOGRAPHIE::LIBELLE_MARCHE, '=', 'HORS MARCHE');
        $this->whereStructureID($allData);
        $AllData = $allData->groupBy(CARTOGRAPHIE::TIERS_NOM)
            ->orderBy($sortField, $sortOrder);

        if ($this->filter->getFilters(request())) {
            $query = $this->filter->applyFilters($query, request());
            $allData = $this->filter->applyFilters($allData, request());
        }

        return [
            'allData' => $allData->get(),
            'retrieveSuppliersOffMarketByDomain' => $query->paginate(APPLICATION::ITEMS_PER_PAGE, ['*'], 'retrieveSuppliersOffMarketByDomain', $page)
                ->appends(request()->except('retrieveSuppliersOffMarketByDomain'))
        ];

    }

    /**
     * Récupère les achats par date.
     *
     * @return array Un tableau contenant les achats par date.
     */
    public function retrieveExpensesPerDate(): array
    {
        $query = $this->CreateBaseRequest()
            ->select(CARTOGRAPHIE::DATE_LOWER, DB::raw('SUM(`montant_ht`) as montant_ht'));
        $this->whereStructureID($query);

        if ($this->filter->getFilters(request())) {
            $query = $this->filter->applyFilters($query, request());
        }

        return $query->groupBy(CARTOGRAPHIE::DATE_LOWER)
            ->get()
            ->map(function ($item) {
                return [
                    CARTOGRAPHIE::DATE_LOWER => $item->date,
                    CARTOGRAPHIE::MONTANT_HT_LOWER => $item->montant_ht,
                ];
            })
            ->toArray();
    }

    /**
     * Récupère les détails des achats.
     *
     * @return array Un tableau contenant les détails des achats.
     */
    public function retrieveDetailsOfExpenses(): array
    {
        $page = request()->input('detailsOfExpenses', 1);
        $sortField = request()->input('sort_by', CARTOGRAPHIE::DATE_LOWER);
        $sortOrder = request()->input('sort_order', 'asc');

        $query = $this->CreateBaseRequest()
            ->select(CARTOGRAPHIE::DATE_LOWER, CARTOGRAPHIE::DOMAINE, CARTOGRAPHIE::SEGMENT, CARTOGRAPHIE::SOUS_SEGMENT, CARTOGRAPHIE::NATURE_DE_LA_PRESTATION, CARTOGRAPHIE::TIERS_NOM, CARTOGRAPHIE::MONTANT_HT_LOWER);
        $this->whereStructureID($query)
            ->orderBy($sortField, $sortOrder);

        $allData = $this->CreateBaseRequest()
            ->select(CARTOGRAPHIE::DATE_LOWER, CARTOGRAPHIE::DOMAINE, CARTOGRAPHIE::SEGMENT, CARTOGRAPHIE::SOUS_SEGMENT, CARTOGRAPHIE::NATURE_DE_LA_PRESTATION, CARTOGRAPHIE::TIERS_NOM, CARTOGRAPHIE::MONTANT_HT_LOWER);
        $this->whereStructureID($query)
            ->orderBy($sortField, $sortOrder);

        if ($this->filter->getFilters(request())) {
            $query = $this->filter->applyFilters($query, request());
            $allData = $this->filter->applyFilters($allData, request());
        }

        return [
            'allData' => $allData->get(),
            'detailsOfExpenses' => $query->paginate(APPLICATION::ITEMS_PER_PAGE, ['*'], 'detailsOfExpenses', $page)
                ->appends(request()->except('detailsOfExpenses'))
        ];
    }

    /**
     * Récupère le top dix des achats par famille.
     *
     * @return array Un tableau contenant le top dix des achats par famille.
     */
    public function retrieveTopTenFamilyPurchase(): array
    {
        $query = $this->CreateBaseRequest()
            ->select(CARTOGRAPHIE::SEGMENT, DB::raw('SUM(`montant_ht`) as montant_ht'));
        $this->whereStructureID($query);
        ;

        if ($this->filter->getFilters(request())) {
            $query = $this->filter->applyFilters($query, request());
        }

        return $query->groupBy(CARTOGRAPHIE::SEGMENT)
            ->take(10)
            ->get()
            ->toArray();
    }

    /**
     * Récupère le taux de couverture des achats.
     *
     * @return array Un tableau contenant le taux de couverture des achats.
     */
    public function retrievePurchaseCoverageRate(): array
    {
        $query = $this->CreateBaseRequest()
            ->select(
                CARTOGRAPHIE::SEGMENT,
                DB::raw('SUM(CASE WHEN libelle_marche = "HORS MARCHE" THEN montant_ht ELSE 0 END) AS hors_marche'),
                DB::raw('SUM(CASE WHEN libelle_marche != "HORS MARCHE" THEN montant_ht ELSE 0 END) AS marche')
            );
        $this->whereStructureID($query);
        ;

        if ($this->filter->getFilters(request())) {
            $query = $this->filter->applyFilters($query, request());
        }

        return $query->groupBy(CARTOGRAPHIE::SEGMENT)
            ->orderBy(CARTOGRAPHIE::SEGMENT)
            ->get()
            ->toArray();
    }

    /**
     * Récupère le marché de renouvellement.
     *
     * @return array Un tableau contenant le marché de renouvellement.
     */
    public function retrieveRenewalMarket()
    {
        if ($this->filter->getFilters(request())['domainSelected'] && $this->filter->getFilters(request())['endDate']) {

            $plus6months = date('Y-m-d', strtotime("+6 months", strtotime($this->filter->getFilters(request())['endDate'])));

            $page = request()->input('renewalMarket', 1);

            $query = $this->CreateBaseRequest()
                ->select(CARTOGRAPHIE::LIBELLE_MARCHE, DB::raw('MAX(date_fin) as date_fin'));
            $this->whereStructureID($query);

            $query->where(CARTOGRAPHIE::DOMAINE, $this->filter->getFilters(request())['domainSelected'])
                ->whereBetween('date_fin', [$this->filter->getFilters(request())['endDate'], $plus6months])
                ->groupBy(CARTOGRAPHIE::LIBELLE_MARCHE);

            $allData = $this->CreateBaseRequest()
                ->select(CARTOGRAPHIE::LIBELLE_MARCHE, DB::raw('MAX(date_fin) as date_fin'));
            $this->whereStructureID($query);

            $allData
                ->where(CARTOGRAPHIE::DOMAINE, $this->filter->getFilters(request())['domainSelected'])
                ->whereBetween('date_fin', [$this->filter->getFilters(request())['endDate'], $plus6months])
                ->groupBy(CARTOGRAPHIE::LIBELLE_MARCHE);

            if ($this->filter->getFilters(request())['directionSelected']) {
                $query->where(CARTOGRAPHIE::LIBELLE_DIRECTION, $this->filter->getFilters(request())['directionSelected']);
                $allData->where(CARTOGRAPHIE::LIBELLE_DIRECTION, $this->filter->getFilters(request())['directionSelected']);
            }

            if ($this->filter->getFilters(request())['serviceSelected']) {
                $query->where(CARTOGRAPHIE::LIBELLE_SERVICE, $this->filter->getFilters(request())['serviceSelected']);
                $allData->where(CARTOGRAPHIE::LIBELLE_SERVICE, $this->filter->getFilters(request())['serviceSelected']);
            }


            return [
                'allData' => $allData->get(),
                'renewalMarket' => $query->paginate(APPLICATION::ITEMS_PER_PAGE, ['*'], 'renewalMarket', $page)
                    ->appends(request()->except('renewalMarket'))
            ];
        } else {
            return [
                'allData' => $this->CreateBaseRequest()
                    ->where(CARTOGRAPHIE::STRUCTURE_ID, -1)
                    ->get(),
                'renewalMarket' => $this->CreateBaseRequest()
                    ->where(CARTOGRAPHIE::STRUCTURE_ID, -1)
                    ->paginate(10)
            ];
        }
    }

    /**
     * Récupère le marché par montant.
     *
     * @return array|null Un tableau contenant le marché par montant, ou null si aucun domaine n'est sélectionné.
     */
    public function retrieveMarketByAmount(): ?array
    {
        if ($this->filter->getFilters(request())['domainSelected']) {
            $query = $this->CreateBaseRequest()
                ->select(
                    CARTOGRAPHIE::LIBELLE_MARCHE,
                    DB::raw('MAX(domaine) as domaine'),
                    DB::raw('SUM(`montant_ht`) as montant_ht')
                );
            $this->whereStructureID($query);
            $query
                ->groupBy(CARTOGRAPHIE::LIBELLE_MARCHE);

            if ($this->filter->getFilters(request())) {
                $query = $this->filter->applyFilters($query, request());
            }

            return $query->get()->toArray();
        } else {
            return null;
        }
    }

    /**
     * Récupère le marché par montant pour l'onglet.
     *
     * @return array Un tableau contenant le marché par montant pour l'onglet.
     */
    public function retrieveMarketByAmountTab()
    {
        if ($this->filter->getFilters(request())['domainSelected']) {
            $page = request()->input('marketByAmount', 1);

            $sortField = request()->input('sort_by', CARTOGRAPHIE::LIBELLE_MARCHE);
            $sortOrder = request()->input('sort_order', 'asc');

            $allowedSortFields = [CARTOGRAPHIE::LIBELLE_MARCHE, CARTOGRAPHIE::SEGMENT, CARTOGRAPHIE::MONTANT_HT_LOWER];
            if (!in_array($sortField, $allowedSortFields)) {
                $sortField = CARTOGRAPHIE::LIBELLE_MARCHE;
            }

            $query = $this->CreateBaseRequest()
                ->select(
                    CARTOGRAPHIE::LIBELLE_MARCHE,
                    DB::raw('MAX(domaine) as domaine'),
                    DB::raw('MAX(segment) as segment'),
                    DB::raw('SUM(`montant_ht`) as montant_ht')
                );
            $this->whereStructureID($query);
            $query->groupBy(CARTOGRAPHIE::LIBELLE_MARCHE)
                ->orderBy($sortField, $sortOrder);

            $allData = $this->CreateBaseRequest()
                ->select(
                    CARTOGRAPHIE::LIBELLE_MARCHE,
                    DB::raw('MAX(domaine) as domaine'),
                    DB::raw('MAX(segment) as segment'),
                    DB::raw('SUM(`montant_ht`) as montant_ht')
                );
            $this->whereStructureID($allData);
            $allData->groupBy(CARTOGRAPHIE::LIBELLE_MARCHE)
                ->orderBy($sortField, $sortOrder);

            if ($this->filter->getFilters(request())) {
                $query = $this->filter->applyFilters($query, request());
                $allData = $this->filter->applyFilters($allData, request());
            }


            return [
                'allData' => $allData->get(),
                'marketByAmount' => $query->paginate(APPLICATION::ITEMS_PER_PAGE, ['*'], 'marketByAmount', $page)
                    ->appends(request()->except('marketByAmount'))
            ];
        } else {
            return [
                'allData' => $this->CreateBaseRequest()
                    ->where(CARTOGRAPHIE::STRUCTURE_ID, -1)
                    ->get(),
                'marketByAmount' => $this->CreateBaseRequest()
                    ->where(CARTOGRAPHIE::STRUCTURE_ID, -1)
                    ->paginate(10)
            ];
        }
    }

    /**
     * Applique le filtre StructureId à la requête.
     *
     * @param \Illuminate\Database\Query\Builder $query La requête à laquelle appliquer le filtre.
     * @return \Illuminate\Database\Query\Builder requête avec le filtre appliqué.
     */
    public function whereStructureId($query)
    {
        return $query->where(CARTOGRAPHIE::STRUCTURE_ID, Auth::user()->structure_id);
    }

    /**
     * Crée une nouvelle requête de base.
     *
     * @return \Illuminate\Database\Query\Builder La nouvelle requête de base.
     */
    public function CreateBaseRequest(): \Illuminate\Database\Query\Builder
    {
        return DB::table(CARTOGRAPHIE::CSV_DONNEES_CLIENT);
    }
}
