<?php

namespace App\Services\AssetsHealth;

use App\Models\AssetHealthHistory;
use App\Models\AssetHealthReportDetail;
use App\Models\AssetHealthReports;
use App\Models\AssetHealthTests;
use App\Notifications\AssetsHealthReportNotification;
use App\Repositories\AssetsHealth\AssetsHealthReportRepository;
use App\Services\AssetsHealth\AssetsHealthDashboardService;
use App\User;
use Log;

class AssetsHealthReportService
{
    /**
     * Create a new instance of the class.
     *
     * @param AssetsHealthReportRepository $assetHealthReportRepository The repository for asset health reports.
     */
    public function __construct(
        protected AssetsHealthReportRepository $assetHealthReportRepository,
        protected AssetsHealthDashboardService $assetsHealthDashboardService
    )
    {
    }

    /**
     * Save health test reports for the given asset health history.
     *
     * @param AssetHealthHistory $history The asset health history instance.
     *
     * @return array The count of saved test reports.
     */
    public function saveHealthTestReports(AssetHealthHistory $history)
    {
        setUnlimitedExecutionTimeAndMemoryLimit();

        $healthTests = AssetHealthTests::all();
        $totalCount = 0;

        foreach ($healthTests as $tests) {
            $testData = $this->getHealthTestFunction($tests->slug);
            $testCount = $this->storeTestReports($testData, $tests, $tests->category_id, $history);

            $totalCount += $testCount;
        }

        return ['count' => $totalCount];
    }

    /**
     * Store the test reports for the given test data and asset health history.
     *
     * @param \Illuminate\Database\Eloquent\Collection|null $testData The test data collection.
     * @param AssetHealthTests $test The asset health test instance.
     * @param int $categoryId The category ID of the test.
     * @param AssetHealthHistory $history The asset health history instance.
     *
     * @return int The count of stored test reports.
     */
    public function storeTestReports($testData, $tests, $categoryId, $history)
    {
        $testAssetsId = null;

        $testResultCount = 0;
        $ignoredAssetsCount = 0;

        if ($testData && $tests->status) {
            $testAssetsId = $testData->get()->pluck('id');
            $testResultCount = $testData->count();
        }

        $previousReport = AssetHealthReports::where('test_id', $tests->id)->where('category_id', $categoryId)->orderByDesc('id')->first();

        $report = AssetHealthReports::create([
            'test_id' => $tests->id,
            'category_id' => $categoryId,
            'history_id' => $history->id,
            'test_count' => $testResultCount
        ]);

        $reportId = $report->id;

        if ($testAssetsId) {
            $ignoredAssetsCount = $this->storeTestReportDetails($reportId, $testAssetsId, $previousReport);
        }

        $report->update([
            'test_count' => ($testResultCount - $ignoredAssetsCount)
        ]);

        return $testResultCount;
    }

    /**
     * Store the test report details for the given report ID, test assets IDs, and previous report.
     *
     * @param int $reportId The ID of the report.
     * @param array $testAssetsId The IDs of the test assets.
     * @param AssetHealthReports|null $previousReport The previous report instance.
     *
     * @return int The count of ignored assets.
     */
    public function storeTestReportDetails($reportId, $testAssetsId, $previousReport)
    {
        $ignoredAssets = [];

        if ($previousReport) {
            $ignoredAssets = AssetHealthReportDetail::where('asset_health_report_id', $previousReport->id)
            ->where('is_ignored', 1)
            ->pluck('asset_id')
            ->toArray();
        }

        foreach ($testAssetsId as $assetId) {
            $isIgnored = 0;

            if (in_array($assetId, $ignoredAssets)) {
                $isIgnored = 1;
            }

            AssetHealthReportDetail::create([
                'asset_health_report_id' => $reportId,
                'asset_id' => $assetId,
                'is_ignored' => $isIgnored
            ]);
        }

        return count($ignoredAssets);
    }

    /**
     * Get the health test data based on the given key.
     *
     * @param string $key The key to determine the health test data method.
     *
     * @return mixed The health test data.
     */
    public function getHealthTestFunction($key)
    {
        $methodMap = config('asset-health.method_map');

        // Check if the key exists in the method map, then execute the corresponding method
        if (array_key_exists($key, $methodMap)) {
            return $this->assetHealthReportRepository->{$methodMap[$key]}();
        }
    }

    /**
     * Get asset health details by asset ID.
     *
     * @param int $assetId The ID of the asset.
     *
     * @return array The asset health details.
     */
    public function getAssetHealthDetailByAsset($assetId)
    {
        $healthCategories = $this->assetsHealthDashboardService->getCategories();
        $assetHealthDetails = [];

        foreach ($healthCategories as $categories) {
            $totalIssueCount = 0;
            $healthTests = AssetHealthTests::where('category_id', $categories->id)->get();

            foreach ($healthTests as $tests) {
                $issueCount = $this->getTestsReportForAsset($tests->id, $assetId)->count();
                $assetHealthDetails[$categories->category_name][$tests->test_name] = $issueCount;
                $totalIssueCount = $totalIssueCount + $issueCount;
            }

            $assetHealthDetails[$categories->category_name]['issueCount'] = $totalIssueCount;
        }

        return $assetHealthDetails;
    }

    /**
     * Get test reports for a specific asset and test.
     *
     * @param int $testId The ID of the test.
     * @param int $assetId The ID of the asset.
     *
     * @return \Illuminate\Database\Eloquent\Builder The query builder for test reports.
     */
    public function getTestsReportForAsset($testId, $assetId)
    {
        $latestHealthHistory = AssetHealthHistory::orderBy('created_at', 'desc')->first();

        $assets = AssetHealthReports::where('test_id', $testId)
            ->join('asset_health_report_details', 'asset_health_report_details.asset_health_report_id', 'asset_health_reports.id')
            ->where('asset_health_report_details.asset_id', $assetId);

        if ($latestHealthHistory) {
            $assets->where('asset_health_reports.history_id', $latestHealthHistory->id);
        }

        return $assets;
    }

    /**
     * Send asset health PDF report via email to specified users.
     *
     * @param array $data The data containing user IDs.
     *
     * @return bool True if the email notification is sent successfully, false otherwise.
     */
    public function sendEmailAssetHealthPdfReport($userData)
    {
        try {
            $users = User::whereIn('id', $userData['users'])->get();

            foreach ($users as $user) {
                $user->notify(new AssetsHealthReportNotification($user));
            }

            return true;
        } catch (\Exception $e) {
            Log::error($e->getMessage());

            return false;
        }

    }
}
