<?php

namespace App\Services\AssetsHealth;

use App\Repositories\AssetHealthHistoryRepository;

use Carbon\Carbon;

class AssetsHealthHistoryService
{
    /**
     * Constructor method for the AssetHealthController class.
     *
     * @param AssetHealthHistoryRepository $assetHealthHistoryRepo The repository for asset health history data.
     */
    public function __construct(protected AssetHealthHistoryRepository $assetHealthHistoryRepo)
    {
    }

    /**
     * Get the start date for the date range.
     *
     * @return \Carbon\Carbon The start date for the date range.
     */
    public function getFromDate()
    {
        return Carbon::now()->subDays(84)->startOfWeek();
    }

    /**
     * Get the end date for the date range.
     *
     * @return \Carbon\Carbon The end date for the date range.
     */
    public function getToDate()
    {
        return  Carbon::now()->endOfDay();
    }

    /**
     * Get assets health report data for a given date range.
     *
     * @param array $data The data containing the date range and other parameters.
     *
     * @return array An array containing the formatted data and week names.
     */
    public function assetsHealthReportData($data)
    {
        $assetsHealthData = $this->assetHealthHistoryRepo->getAssetHealthReportDataInWeek($data);

        $weeks = get_asset_health_week_range_count($data['dateFrom'], $data['dateTo']);

        $datas = $this->getFormattedData($assetsHealthData, $weeks);
        $weekNames = collect($weeks)->flatten()->toArray();

        return ['datas' => $datas, 'weeks' => $weekNames];
    }

    /**
     * Filter asset health report data based on provided criteria.
     *
     * @param array $data The filter criteria.
     *                    - dateFrom: The start date.
     *                    - dateTo: The end date.
     *                    - testIds: The array of test IDs.
     *                    - categoryIds: The array of category IDs.
     *
     * @return array An array containing filtered data, weeks, labels, ykeys, and color array.
     */
    public function assetsHealthReportDataFilter($data)
    {
        $weeks = get_asset_health_week_range_count($data['dateFrom'], $data['dateTo']);

        $testIds = $data['testIds'] ?? [];
        $categoryIds = $data['categoryIds'] ?? [];

        $testData = $this->getHealthDataByType($testIds, 'testId', $data);
        $categoryData = $this->getHealthDataByType($categoryIds, 'categoryId', $data);

        $formattedData = $this->formattedFilterData($testData, $categoryData, $weeks);

        $weekNames = collect($weeks)->flatten()->toArray();
        $uniqueLabels = array_unique($formattedData['labelArray']);
        $uniqueYkeys = array_unique($formattedData['ykeys']);
        $colorArray = array_unique($formattedData['colorArray']);

        return [
            'datas' => $formattedData['formattedData'],
            'weeks' => $weekNames,
            'labels' => $uniqueLabels,
            'ykeys' => $uniqueYkeys,
            'colorArray' => $colorArray
        ];
    }

    /**
     * Get health data based on provided IDs and type key.
     *
     * @param array $ids      The array of IDs.
     * @param string $typeKey The type key ('testId' or 'categoryId').
     * @param array $data     The filter criteria.
     *
     * @return array An array containing health data for each ID.
     */
    private function getHealthDataByType($ids, $typeKey, $data)
    {
        $resultData = [];

        foreach ($ids as $id) {
            $data[$typeKey] = $id === "all" ? null : $id;
            $data[$typeKey === 'testId' ? 'categoryId' : 'testId'] = null;

            $resultData[$id] = $this->assetHealthHistoryRepo->getAssetHealthReportDataInWeek($data);
        }

        return $resultData;
    }

    /**
     * Format asset health history data.
     *
     * @param array $assetHistories The asset health histories.
     * @param array $weeks          The weeks array.
     *
     * @return array The formatted data.
     */
    public function getFormattedData($assetHistories, array $weeks)
    {
        $formattedData = [];
        $assetHealthHistoryData = $assetHistories->toArray();

        foreach ($weeks as $weekNumber => $weekName) {
            $totalIssues = 0;

            if (in_array($weekNumber, array_column($assetHealthHistoryData, 'weekDay'))) {
                $totalIssues = array_column($assetHealthHistoryData, 'totalIssues', 'weekDay')[$weekNumber];
            }

            $formattedData[] = [
                'weekDate' => $weekName,
                'weekDay' => $weekNumber,
                'totalIssues' => $totalIssues,
            ];
        }

        return $formattedData;
    }

    /**
     * Format filter data for asset health reports.
     *
     * @param array $testAssetHistoriesArray     The array of test asset histories.
     * @param array $categoryAssetHistoriesArray The array of category asset histories.
     * @param array $weeks                       The weeks array.
     *
     * @return array The formatted filter data.
     */
    public function formattedFilterData(array $testAssetHistoriesArray, array $categoryAssetHistoriesArray, array $weeks)
    {
        $formattedData = [];
        $labelArray = [];
        $ykeys = [];
        $colorArray = [];

        foreach ($weeks as $weekNumber => $weekName) {
            // Initialize an array for each week
            $weekData = [
                'weekDate' => $weekName,
                'weekDay' => $weekNumber
            ];

            $labelArray = $this->addTestDataLabels($testAssetHistoriesArray, $labelArray, $ykeys, $colorArray, $weekNumber, $weekData);
            $labelArray = $this->addCategoryDataLabels($categoryAssetHistoriesArray, $labelArray, $ykeys, $colorArray, $weekNumber, $weekData);

            // Add the week data to the formatted data array
            $formattedData[] = $weekData;
        }

        return compact('formattedData', 'labelArray', 'ykeys', 'colorArray');
    }

    /**
     * Add labels for test data to the label array.
     *
     * @param array $testAssetHistoriesArray The array containing test asset histories.
     * @param array $labelArray The array of labels to which test labels will be added.
     * @param array $ykeys The array of ykeys used for chart data.
     * @param array $colorArray The array of colors used for chart data.
     * @param int $weekNumber The week number for which data is being processed.
     * @param array $weekData The data array for the current week.
     *
     * @return array The updated label array.
     */
    private function addTestDataLabels($testAssetHistoriesArray, $labelArray, &$ykeys, &$colorArray, $weekNumber, &$weekData)
    {
        foreach ($testAssetHistoriesArray as $testId => $assetHistories) {
            $assetHealthHistoryData = $assetHistories->toArray();
            $test = $this->assetHealthHistoryRepo->getTest($testId);
            $labelArray[] = $this->getTestLabel($test);
            $totalIssuesKey = 'testIssues' . ($testId);
            $ykeys[] = $totalIssuesKey;
            $colorArray[] = config('asset-health.map_colors')[$test->slug];
            $totalIssues = $this->getTotalIssues($assetHealthHistoryData, $weekNumber);
            $weekData[$totalIssuesKey] = $totalIssues;
        }

        return $labelArray;
    }

    /**
     * Generate a label for a test based on its configuration.
     *
     * @param object $test The test object.
     *
     * @return string The formatted test label.
     */
    private function getTestLabel($test)
    {
        return "<span style='background-color:" . config('asset-health.map_colors')[$test->slug] . "'></span> " . $test->test_name;
    }

    /**
     * Add labels for category data to the label array.
     *
     * @param array $categoryAssetHistoriesArray The array containing category asset histories.
     * @param array $labelArray The array of labels to which category labels will be added.
     * @param array $ykeys The array of ykeys used for chart data.
     * @param array $colorArray The array of colors used for chart data.
     * @param int $weekNumber The week number for which data is being processed.
     * @param array $weekData The data array for the current week.
     *
     * @return array The updated label array.
     */
    private function addCategoryDataLabels($categoryAssetHistoriesArray, $labelArray, &$ykeys, &$colorArray, $weekNumber, &$weekData)
    {
        foreach ($categoryAssetHistoriesArray as $categoryId => $assetHistories) {
            $assetHealthHistoryData = $assetHistories->toArray();
            $labelArray = $this->addCategoryLabel($categoryId, $labelArray);
            $colorArray[] = $this->getCategoryColor($categoryId);
            $totalIssuesKey = 'categoryIssues' . ($categoryId);
            $ykeys[] = $totalIssuesKey;
            $totalIssues = $this->getTotalIssues($assetHealthHistoryData, $weekNumber);
            $weekData[$totalIssuesKey] = $totalIssues;
        }

        return $labelArray;
    }

    /**
     * Add a category label to the label array.
     *
     * @param mixed $categoryId The ID of the category.
     * @param array $labelArray The array of labels to which the category label will be added.
     *
     * @return array The updated label array.
     */
    private function addCategoryLabel($categoryId, $labelArray)
    {
        if ($categoryId != "all") {
            $category = $this->assetHealthHistoryRepo->getCategory($categoryId);
            $labelArray[] = "<span style='background-color:" . config('asset-health.map_colors')[$category->slug] . "'></span> Total " . $category->category_name;
        } else {
            $labelArray[] = "<span style='background-color:" . config('asset-health.map_colors')['all'] . "'></span> Total Issues";
        }

        return $labelArray;
    }

    /**
     * Get the color for a category based on its ID.
     *
     * @param mixed $categoryId The ID of the category.
     *
     * @return string The color code for the category.
     */
    private function getCategoryColor($categoryId)
    {
        if ($categoryId != "all") {
            $category = $this->assetHealthHistoryRepo->getCategory($categoryId);

            return config('asset-health.map_colors')[$category->slug];
        } else {
            return config('asset-health.map_colors')['all'];
        }
    }

    /**
     * Get the total issues for a specific week.
     *
     * @param array $assetHealthHistoryData The array of asset health history data.
     * @param int $weekNumber The week number for which total issues are being calculated.
     *
     * @return int The total number of issues for the specified week.
     */
    private function getTotalIssues($assetHealthHistoryData, $weekNumber)
    {
        $totalIssues = 0;

        if (in_array($weekNumber, array_column($assetHealthHistoryData, 'weekDay'))) {
            $totalIssuesArray = array_column($assetHealthHistoryData, 'totalIssues', 'weekDay');
            $totalIssues = isset($totalIssuesArray[$weekNumber]) ? $totalIssuesArray[$weekNumber] : 0;
        }

        return $totalIssues;
    }
}
