<?php

namespace App\Services;

use App\Models\Surveillance;
use App\Models\SurveillanceCase;
use App\Models\CaseLabResult;
use SebastianBergmann\CodeCoverage\Report\Xml\Totals;

class DashboardService
{
    private function totalTested($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {
        return SurveillanceCase::where('surveillance_id', $surveillanceId)
            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
                $q->whereRaw("(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek])
                    ->whereRaw("(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek]);
            })
            ->distinct('lab_code')
            ->count('lab_code');
    }

    /*
    |--------------------------------------------------------------------------
    | Overview Summary Cards
    |--------------------------------------------------------------------------
    */

    public function summaryCards()
    {
        $today = date('Y-m-d');

        $currentFrom = date('Y-m-d', strtotime('-6 days'));
        $currentTo = $today;

        $prevFrom = date('Y-m-d', strtotime('-13 days'));
        $prevTo = date('Y-m-d', strtotime('-7 days'));

        $results = [];

        $programs = Surveillance::where('id', '!=', 6)
            ->orderBy('id')
            ->get();

        foreach ($programs as $program) {

            $current = SurveillanceCase::where('surveillance_id', $program->id)
                ->whereBetween('case_date', [$currentFrom, $currentTo])
                ->distinct('lab_code')
                ->count('lab_code');

            $previous = SurveillanceCase::where('surveillance_id', $program->id)
                ->whereBetween('case_date', [$prevFrom, $prevTo])
                ->distinct('lab_code')
                ->count('lab_code');

            $percentChange = $previous > 0
                ? round((($current - $previous) / $previous) * 100, 1)
                : ($current > 0 ? 100 : 0);

            $results[] = [
                'surveillance_id' => $program->id,
                'code' => $program->code,
                'current_total' => $current,
                'previous_total' => $previous,
                'percent_change' => $percentChange
            ];
        }

        /*
        |--------------------------------------------------------------------------
        | A/H5N1 Summary Card
        |--------------------------------------------------------------------------
        */

        $h5n1Current = SurveillanceCase::join('case_lab_results', function ($join) {
            $join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
                ->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
        })
            ->whereBetween('surveillance_cases.case_date', [$currentFrom, $currentTo])
            ->where('case_lab_results.subtype', 'A/H5N1')
            ->where('surveillance_cases.surveillance_id', '!=', 6)
            ->distinct('surveillance_cases.lab_code')
            ->count('surveillance_cases.lab_code');

        $h5n1Previous = SurveillanceCase::join('case_lab_results', function ($join) {
            $join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
                ->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
        })
            ->whereBetween('surveillance_cases.case_date', [$prevFrom, $prevTo])
            ->where('case_lab_results.subtype', 'A/H5N1')
            ->where('surveillance_cases.surveillance_id', '!=', 6)
            ->distinct('surveillance_cases.lab_code')
            ->count('surveillance_cases.lab_code');

        $h5n1Percent = $h5n1Previous > 0
            ? round((($h5n1Current - $h5n1Previous) / $h5n1Previous) * 100, 1)
            : ($h5n1Current > 0 ? 100 : 0);

        $results[] = [
            'surveillance_id' => null,
            'code' => 'H5N1',
            'current_total' => $h5n1Current,
            'previous_total' => $h5n1Previous,
            'percent_change' => $h5n1Percent
        ];

        return $results;
    }


    /*
    |--------------------------------------------------------------------------
    | Program Summary
    |--------------------------------------------------------------------------
    */

    public function afiTrend(
        $surveillanceId,
        $startYear,
        $startWeek,
        $endYear,
        $endWeek
    ) {

        $rows = CaseLabResult::join(
            'surveillance_cases',
            'case_lab_results.lab_code',
            '=',
            'surveillance_cases.lab_code'
        )

            ->where(
                'surveillance_cases.surveillance_id',
                $surveillanceId
            )

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {

                $q->whereRaw(
                    "(year_data > ?
                        OR (
                            year_data = ?
                            AND week_data >= ?
                        )
                    )",
                    [$startYear, $startYear, $startWeek]
                )

                    ->whereRaw(
                        "(year_data < ?
                            OR (
                                year_data = ?
                                AND week_data <= ?
                            )
                        )",
                        [$endYear, $endYear, $endWeek]
                    );
            })

            ->where('case_lab_results.is_positive', 1)

            ->whereNotNull('case_lab_results.pathogen_name')

            ->selectRaw("

                surveillance_cases.year_data as year,
                surveillance_cases.week_data as period,

                case_lab_results.pathogen_name as pathogen,
                case_lab_results.subtype,

                CASE

                    WHEN LOWER(case_lab_results.pathogen_name)
                        LIKE '%influenza%'

                        OR LOWER(case_lab_results.pathogen_name)
                        LIKE '%covid%'

                        OR LOWER(case_lab_results.pathogen_name)
                        LIKE '%sars-cov%'

                        THEN 'section_1'

                    WHEN LOWER(case_lab_results.indicator)
                        LIKE '%serum%'

                        THEN 'section_3'

                    ELSE 'section_2'

                END as afi_section,

                COUNT(DISTINCT surveillance_cases.lab_code)
                    as total_positive

            ")

            ->groupBy(
                'surveillance_cases.year_data',
                'surveillance_cases.week_data',
                'pathogen',
                'subtype',
                'afi_section'
            )

            ->orderBy('surveillance_cases.year_data')
            ->orderBy('surveillance_cases.week_data')

            ->get();

        return [

            'section_1' => $rows
                ->where('afi_section', 'section_1')
                ->values(),

            'section_2' => $rows
                ->where('afi_section', 'section_2')
                ->values(),

            'section_3' => $rows
                ->where('afi_section', 'section_3')
                ->values()

        ];
    }


    public function afiCaseTrend(
        $surveillanceId,
        $startYear,
        $startWeek,
        $endYear,
        $endWeek
    ) {

        /*
        |--------------------------------------------------------------------------
        | AFI SECTION SQL
        |--------------------------------------------------------------------------
        */

        $afiSectionSql = "

        CASE

            WHEN LOWER(case_lab_results.indicator)
                LIKE '%influenza%'

                OR LOWER(case_lab_results.indicator)
                LIKE '%covid%'

                THEN 'section_1'

            WHEN LOWER(case_lab_results.indicator)
                LIKE '%serum%'

                THEN 'section_3'

            ELSE 'section_2'

        END

    ";

        /*
        |--------------------------------------------------------------------------
        | ALL TESTED CASES
        |--------------------------------------------------------------------------
        |
        | THIS MUST INCLUDE:
        | - positive
        | - negative
        | - weeks with no positives
        |
        */

        $totalCases = CaseLabResult::join(
            'surveillance_cases',
            'case_lab_results.lab_code',
            '=',
            'surveillance_cases.lab_code'
        )

            ->where(
                'surveillance_cases.surveillance_id',
                $surveillanceId
            )

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {

                $q->whereRaw(
                    "(year_data > ?
                    OR (
                        year_data = ?
                        AND week_data >= ?
                    )
                )",
                    [
                        $startYear,
                        $startYear,
                        $startWeek
                    ]
                )

                    ->whereRaw(
                        "(year_data < ?
                            OR (
                                year_data = ?
                                AND week_data <= ?
                            )
                        )",
                        [
                            $endYear,
                            $endYear,
                            $endWeek
                        ]
                    );

            })

            ->selectRaw("

                surveillance_cases.year_data as year,
                surveillance_cases.week_data as period,

                {$afiSectionSql}
                    as afi_section,

                COUNT(DISTINCT case_lab_results.lab_code)
                    as total_cases

            ")

            ->groupBy(
                'surveillance_cases.year_data',
                'surveillance_cases.week_data',
                'afi_section'
            )

            ->orderBy('surveillance_cases.year_data')

            ->orderBy('surveillance_cases.week_data')

            ->get();

        /*
        |--------------------------------------------------------------------------
        | KEYED TOTALS
        |--------------------------------------------------------------------------
        */

        $totalCasesKeyed = $totalCases->keyBy(

            fn($r) =>

            $r->year .
            '-' .
            $r->period .
            '-' .
            $r->afi_section

        );

        /*
        |--------------------------------------------------------------------------
        | POSITIVE RESULTS
        |--------------------------------------------------------------------------
        */

        $rows = CaseLabResult::join(
            'surveillance_cases',
            'case_lab_results.lab_code',
            '=',
            'surveillance_cases.lab_code'
        )

            ->where(
                'surveillance_cases.surveillance_id',
                $surveillanceId
            )

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {

                $q->whereRaw(
                    "(year_data > ?
                        OR (
                            year_data = ?
                            AND week_data >= ?
                        )
                    )",
                    [
                        $startYear,
                        $startYear,
                        $startWeek
                    ]
                )

                    ->whereRaw(
                        "(year_data < ?
                            OR (
                                year_data = ?
                                AND week_data <= ?
                            )
                        )",
                        [
                            $endYear,
                            $endYear,
                            $endWeek
                        ]
                    );

            })

            ->where('case_lab_results.is_positive', 1)

            ->whereNotNull(
                'case_lab_results.pathogen_name'
            )

            ->where(
                'case_lab_results.pathogen_name',
                '!=',
                ''
            )

            ->selectRaw("

                surveillance_cases.year_data as year,
                surveillance_cases.week_data as period,

                CASE

                    WHEN LOWER(case_lab_results.pathogen_name)
                        LIKE '%influenza%'

                        THEN 'Influenza'

                    ELSE case_lab_results.pathogen_name

                END as pathogen,

                case_lab_results.subtype,

                {$afiSectionSql}
                    as afi_section,

                COUNT(DISTINCT case_lab_results.lab_code)
                    as total_positive

            ")

            ->groupBy(
                'surveillance_cases.year_data',
                'surveillance_cases.week_data',
                'pathogen',
                'subtype',
                'afi_section'
            )

            ->orderBy('surveillance_cases.year_data')

            ->orderBy('surveillance_cases.week_data')

            ->get()

            ->map(function ($r) use ($totalCasesKeyed) {

                $key =

                    $r->year .
                    '-' .
                    $r->period .
                    '-' .
                    $r->afi_section;

                $r->total_cases =

                    $totalCasesKeyed[$key]
                        ->total_cases ?? 0;

                $r->positivity_rate =

                    $r->total_cases > 0

                    ? round(
                        (
                            $r->total_positive
                            / $r->total_cases
                        ) * 100,
                        1
                    )

                    : 0;

                return $r;

            });

        /*
        |--------------------------------------------------------------------------
        | RETURN
        |--------------------------------------------------------------------------
        */

        return [

            'section_1' => [

                'rows' => $rows
                    ->where(
                        'afi_section',
                        'section_1'
                    )
                    ->values(),

                'totals' => $totalCases
                    ->where(
                        'afi_section',
                        'section_1'
                    )
                    ->values()

            ],

            'section_2' => [

                'rows' => $rows
                    ->where(
                        'afi_section',
                        'section_2'
                    )
                    ->values(),

                'totals' => $totalCases
                    ->where(
                        'afi_section',
                        'section_2'
                    )
                    ->values()

            ],

            'section_3' => [

                'rows' => $rows
                    ->where(
                        'afi_section',
                        'section_3'
                    )
                    ->values(),

                'totals' => $totalCases
                    ->where(
                        'afi_section',
                        'section_3'
                    )
                    ->values()

            ]

        ];

    }
    public function programSummaryFast($surveillanceId, $year = null, $week = null, $dateFrom = null, $dateTo = null)
    {
        $query = SurveillanceCase::leftJoin(
            'case_lab_results',
            'surveillance_cases.lab_code',
            '=',
            'case_lab_results.lab_code'
        )
            ->where('surveillance_cases.surveillance_id', $surveillanceId);

        if ($dateFrom && $dateTo) {
            $query->whereBetween('surveillance_cases.case_date', [$dateFrom, $dateTo]);
        } else {
            $query->where('surveillance_cases.year_data', $year)
                ->where('surveillance_cases.week_data', $week);
        }

        $row = $query->selectRaw("
            COUNT(DISTINCT surveillance_cases.lab_code) as total_cases,

            COUNT(DISTINCT CASE
                WHEN case_lab_results.is_positive = 1
                THEN surveillance_cases.lab_code
            END) as overall_positive,

            COUNT(DISTINCT CASE
                WHEN case_lab_results.is_positive = 1
                AND (
                    LOWER(case_lab_results.pathogen_name) LIKE '%influenza%'
                )
                THEN surveillance_cases.lab_code
            END) as influenza_positive,

            COUNT(DISTINCT CASE
                WHEN case_lab_results.is_positive = 1
                AND (
                    LOWER(case_lab_results.pathogen_name) LIKE '%sars%'
                )
                THEN surveillance_cases.lab_code
            END) as covid_positive
        ")->first();

        if (!$row || $row->total_cases == 0) {
            return [
                'cases' => 0,
                'overall_rate' => 0,
                'influenza_rate' => 0,
                'covid_rate' => 0
            ];
        }

        return [
            'cases' => $row->total_cases,
            'overall_rate' => round(($row->overall_positive / $row->total_cases) * 100, 1),
            'influenza_rate' => round(($row->influenza_positive / $row->total_cases) * 100, 1),
            'covid_rate' => round(($row->covid_positive / $row->total_cases) * 100, 1),
        ];
    }
    public function programSummary($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {
        $dateTo = now()->toDateString();
        $dateFrom = now()->subDays(7)->toDateString();

        $current = $this->programSummaryFast(
            $surveillanceId,
            null,
            null,
            $dateFrom,
            $dateTo
        );

        $prevFrom = date('Y-m-d', strtotime($dateFrom . ' -7 days'));
        $prevTo = date('Y-m-d', strtotime($dateFrom . ' -1 day'));

        $previous = $this->programSummaryFast(
            $surveillanceId,
            null,
            null,
            $prevFrom,
            $prevTo
        );

        return [
            'cases' => [
                'current' => $current['cases'],
                'previous' => $previous['cases']
            ],
            'hospital_rate' => [
                'current' => 0,
                'previous' => 0
            ],
            'icu_rate' => [
                'current' => 0,
                'previous' => 0
            ],
            'positivity_rate' => [
                'current' => $current['overall_rate'],
                'previous' => $previous['overall_rate']
            ],
            'influenza_rate' => [
                'current' => $current['influenza_rate'],
                'previous' => $previous['influenza_rate']
            ],
            'covid_rate' => [
                'current' => $current['covid_rate'],
                'previous' => $previous['covid_rate']
            ],
        ];
    }


    /*
    |--------------------------------------------------------------------------
    | Overview Trend
    |--------------------------------------------------------------------------
    */

    public function aggregateAllPrograms($startYear, $startWeek, $endYear, $endWeek)
    {

        $data = SurveillanceCase::selectRaw("
                surveillance_id,
                year_data as year,
                week_data as period,
                COUNT(*) as total
            ")

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {

                $q->whereRaw(
                    "(year_data > ? OR (year_data = ? AND week_data >= ?))",
                    [$startYear, $startYear, $startWeek]
                )

                    ->whereRaw(
                        "(year_data < ? OR (year_data = ? AND week_data <= ?))",
                        [$endYear, $endYear, $endWeek]
                    );

            })

            ->groupBy('surveillance_id', 'year_data', 'week_data')
            ->orderBy('year_data')
            ->orderBy('week_data')
            ->get();


        $programs = Surveillance::pluck('code', 'id');

        $results = [];

        foreach ($data as $row) {

            $code = $programs[$row->surveillance_id];

            $results[$code][] = $row;

        }

        return $results;
    }



    /*
    |--------------------------------------------------------------------------
    | Program Dashboard
    |--------------------------------------------------------------------------
    */





    /*
    |--------------------------------------------------------------------------
    | Trend Single Program
    |--------------------------------------------------------------------------
    */

    public function trendSingleProgram($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {

        $rows = SurveillanceCase::leftJoin(
            'case_lab_results',
            'surveillance_cases.lab_code',
            '=',
            'case_lab_results.lab_code'
        )

            ->where('surveillance_cases.surveillance_id', $surveillanceId)

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {

                $q->whereRaw(
                    "(surveillance_cases.year_data > ? OR (surveillance_cases.year_data = ? AND surveillance_cases.week_data >= ?))",
                    [$startYear, $startYear, $startWeek]
                )

                    ->whereRaw(
                        "(surveillance_cases.year_data < ? OR (surveillance_cases.year_data = ? AND surveillance_cases.week_data <= ?))",
                        [$endYear, $endYear, $endWeek]
                    );

            })

            ->selectRaw("
                surveillance_cases.year_data as year,
                surveillance_cases.week_data as period,

                COUNT(DISTINCT surveillance_cases.lab_code) as total_samples,

                -- Overall positivity
                ROUND(
                    COUNT(DISTINCT CASE
                        WHEN case_lab_results.is_positive = 1
                        THEN surveillance_cases.lab_code
                    END)
                    / NULLIF(COUNT(DISTINCT surveillance_cases.lab_code), 0) * 100
                ,1) as positivity_rate,

                -- Influenza %
                ROUND(
                    COUNT(DISTINCT CASE
                        WHEN case_lab_results.is_positive = 1
                        AND (
                            LOWER(case_lab_results.pathogen_name) LIKE '%influenza%'
                        )
                        THEN surveillance_cases.lab_code
                    END)
                    / NULLIF(COUNT(DISTINCT surveillance_cases.lab_code), 0) * 100
                ,1) as influenza_rate,

                -- COVID %
                ROUND(
                    COUNT(DISTINCT CASE
                        WHEN case_lab_results.is_positive = 1
                        AND (
                            case_lab_results.pathogen_name = 'COVID-19'
                            OR case_lab_results.pathogen_name = 'SARS-CoV-2'
                        )
                        AND case_lab_results.indicator LIKE '%COVID%'
                        THEN surveillance_cases.lab_code
                    END)
                    / NULLIF(COUNT(DISTINCT surveillance_cases.lab_code), 0) * 100
                ,1) as covid_rate,

                -- EV %
                ROUND(
                    COUNT(DISTINCT CASE
                        WHEN case_lab_results.is_positive = 1
                        AND LOWER(case_lab_results.pathogen_name) LIKE '%ev%'
                        THEN surveillance_cases.lab_code
                    END)
                    / NULLIF(COUNT(DISTINCT surveillance_cases.lab_code), 0) * 100
                ,1) as ev_rate,

                -- MPOX %
                ROUND(
                    COUNT(DISTINCT CASE
                        WHEN case_lab_results.is_positive = 1
                        AND LOWER(case_lab_results.pathogen_name) LIKE '%mpox%'
                        THEN surveillance_cases.lab_code
                    END)
                    / NULLIF(COUNT(DISTINCT surveillance_cases.lab_code), 0) * 100
                ,1) as mpox_rate
                            ")

            ->groupBy(
                'surveillance_cases.year_data',
                'surveillance_cases.week_data'
            )

            ->get()
            ->keyBy(fn($r) => $r->year . '-' . $r->period);



        $results = [];

        $year = $startYear;
        $week = $startWeek;

        while (true) {

            $key = $year . '-' . $week;

            if (isset($rows[$key])) {

                $results[] = $rows[$key];

            } else {

                $results[] = [
                    'year' => $year,
                    'period' => $week,
                    'total_samples' => 0,
                    'positivity_rate' => 0
                ];

            }

            if ($year == $endYear && $week == $endWeek)
                break;

            $week++;

            if ($week > 52) {
                $week = 1;
                $year++;
            }

        }

        return $results;

    }
    public function virusTrend($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {
        return CaseLabResult::join(
            'surveillance_cases',
            'case_lab_results.lab_code',
            '=',
            'surveillance_cases.lab_code'
        )

            ->where('surveillance_cases.surveillance_id', $surveillanceId)

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
                $q->whereRaw("(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek])
                    ->whereRaw("(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek]);
            })

            ->selectRaw("
                surveillance_cases.week_data as period,

                COUNT(DISTINCT CASE
                    WHEN case_lab_results.is_positive = 1
                    AND (
                        LOWER(case_lab_results.pathogen_name) LIKE '%influenza%'
                    )
                    THEN surveillance_cases.lab_code
                END) as influenza,

                COUNT(DISTINCT CASE
                    WHEN case_lab_results.is_positive = 1
                    AND (
                        case_lab_results.pathogen_name = 'Positive'
                        OR case_lab_results.pathogen_name = 'SARS-CoV-2'
                    )
                    AND case_lab_results.indicator LIKE '%Covid%'
                    THEN surveillance_cases.lab_code
                END) as covid,

                COUNT(DISTINCT CASE
                    WHEN case_lab_results.is_positive = 1
                    AND LOWER(case_lab_results.pathogen_name) LIKE '%ev%'
                    THEN surveillance_cases.lab_code
                END) as ev,

                COUNT(DISTINCT CASE
                    WHEN case_lab_results.is_positive = 1
                    AND LOWER(case_lab_results.pathogen_name) LIKE '%mpox%'
                    THEN surveillance_cases.lab_code
                END) as mpox
            ")

            ->groupBy('surveillance_cases.week_data')
            ->orderBy('surveillance_cases.week_data')
            ->get();
    }


    /*
    |--------------------------------------------------------------------------
    | Province Distribution (Program)
    |--------------------------------------------------------------------------
    */
    public function provinceCircles($startYear, $startWeek, $endYear, $endWeek)
    {

        return SurveillanceCase::join('case_lab_results', function ($join) {
            $join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
                ->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
        })
            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
                $q->whereRaw(
                    "(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
                    [
                        $startYear * 100 + $startWeek,
                        $endYear * 100 + $endWeek
                    ]
                );
            })
            ->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id not in(6) and case_lab_results.indicator="Influenza"')
            ->selectRaw("
                surveillance_cases.patient_province,
                case_lab_results.subtype as pathogen_name,
                COUNT(DISTINCT surveillance_cases.lab_code) as total
            ")
            ->groupBy(
                'surveillance_cases.patient_province',
                'case_lab_results.subtype'
            )
            ->get();

    }

    /* Start Overview Section */

    public function influenzaSubtypeDetected($startYear, $startWeek, $endYear, $endWeek)
    {
        return SurveillanceCase::join('case_lab_results', function ($join) {
            $join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
                ->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
        })
            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
                $q->whereRaw(
                    "(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
                    [
                        $startYear * 100 + $startWeek,
                        $endYear * 100 + $endWeek
                    ]
                );
            })
            ->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id not in(6) and case_lab_results.indicator="Influenza"')
            ->selectRaw("
                case_lab_results.subtype,
                COUNT(DISTINCT surveillance_cases.lab_code) as total
            ")
            ->groupBy(
                'case_lab_results.subtype'
            )
            ->get();
    }

    public function covidDistributedByAgeGroup($startYear, $startWeek, $endYear, $endWeek)
    {
        return SurveillanceCase::join('case_lab_results', function ($join) {
            $join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
                ->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
        })
            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
                $q->whereRaw(
                    "(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
                    [
                        $startYear * 100 + $startWeek,
                        $endYear * 100 + $endWeek
                    ]
                );
            })
            ->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id not in(6) and case_lab_results.indicator="Covid-19"')
            ->selectRaw("
            CASE
                WHEN patient_age_inday <= 28 THEN '0–28 days'
                WHEN patient_age_inday <= 364 THEN '29 days–11 months'
                WHEN patient_age_inday <= 1460 THEN '1–4 years'
                WHEN patient_age_inday <= 5110 THEN '5–14 years'
                WHEN patient_age_inday <= 8765 THEN '15–24 years'
                WHEN patient_age_inday <= 18250 THEN '25–49 years'
                WHEN patient_age_inday <= 23725 THEN '50–64 years'
                ELSE '65+ years'
            END as age_group,
            CASE
                WHEN patient_age_inday <= 28 THEN 1
                WHEN patient_age_inday <= 364 THEN 2
                WHEN patient_age_inday <= 1460 THEN 3
                WHEN patient_age_inday <= 5110 THEN 4
                WHEN patient_age_inday <= 8765 THEN 5
                WHEN patient_age_inday <= 18250 THEN 6
                WHEN patient_age_inday <= 23725 THEN 7
                ELSE 8
            END as age_order,
            COUNT(*) as total
        ")
            ->groupBy('age_group', 'age_order')
            ->orderBy('age_order')
            ->get();

    }

    public function covidLineageRelativeOverTime($startYear, $startWeek, $endYear, $endWeek)
    {
        return SurveillanceCase::join('case_lab_results', function ($join) {
            $join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
                ->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
        })
            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
                $q->whereRaw(
                    "(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
                    [
                        $startYear * 100 + $startWeek,
                        $endYear * 100 + $endWeek
                    ]
                );
            })
            ->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id=6 and case_lab_results.indicator="Covid-19" and case_lab_results.pathogen_name not in("","unable to align","N/A","NA")')
            ->selectRaw("
                case_lab_results.pathogen_name as lineage,
                concat(surveillance_cases.year_data,'-W',surveillance_cases.week_data) as week,
                COUNT(DISTINCT surveillance_cases.lab_code) as total
            ")
            ->groupBy(
                'case_lab_results.pathogen_name',
                'week'
            )
            ->get();
    }

    public function influenzaRelativeOverTime($startYear, $startWeek, $endYear, $endWeek)
    {
        return SurveillanceCase::join('case_lab_results', function ($join) {
            $join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
                ->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
        })
            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
                $q->whereRaw(
                    "(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
                    [
                        $startYear * 100 + $startWeek,
                        $endYear * 100 + $endWeek
                    ]
                );
            })
            ->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id not in(6) and case_lab_results.indicator="Influenza"')
            ->selectRaw("
                case_lab_results.subtype as lineage,
                concat(surveillance_cases.year_data,'-W',surveillance_cases.week_data) as week,
                COUNT(DISTINCT surveillance_cases.lab_code) as total
            ")
            ->groupBy(
                'case_lab_results.subtype',
                'week'
            )
            ->get();
    }

    /* End Overview Section */

    public function provinceProgram($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {
        return SurveillanceCase::selectRaw("
                surveillance_cases.patient_province,

                COUNT(DISTINCT surveillance_cases.lab_code) as total,

                COUNT(DISTINCT CASE
                    WHEN case_lab_results.is_positive = 1
                    THEN surveillance_cases.lab_code
                END) as positive
            ")

            ->join(
                'case_lab_results',
                'surveillance_cases.lab_code',
                '=',
                'case_lab_results.lab_code'
            )

            ->where('surveillance_cases.surveillance_id', $surveillanceId)

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {

                $q->whereRaw(
                    "(surveillance_cases.year_data > ? OR (surveillance_cases.year_data = ? AND surveillance_cases.week_data >= ?))",
                    [$startYear, $startYear, $startWeek]
                )

                    ->whereRaw(
                        "(surveillance_cases.year_data < ? OR (surveillance_cases.year_data = ? AND surveillance_cases.week_data <= ?))",
                        [$endYear, $endYear, $endWeek]
                    );

            })

            ->groupBy('surveillance_cases.patient_province')
            ->get();
    }

    /*
    |--------------------------------------------------------------------------
    | sentinel sites
    |--------------------------------------------------------------------------
    */
    public function sentinelSites($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {
        return SurveillanceCase::selectRaw("
                sentinel_site_name as name,
                COUNT(DISTINCT lab_code) as total
            ")
            ->where('surveillance_id', $surveillanceId)

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
                $q->whereRaw("(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek])
                    ->whereRaw("(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek]);
            })

            ->groupBy('sentinel_site_name')
            ->orderByDesc('total')
            ->get();
    }

    /*
    |--------------------------------------------------------------------------
    | Pathogen Distribution
    |--------------------------------------------------------------------------
    */

    public function pathogenDistribution($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {
        $total = $this->totalTested($surveillanceId, $startYear, $startWeek, $endYear, $endWeek);

        $rows = CaseLabResult::where('case_lab_results.surveillance_id', $surveillanceId)

            ->whereIn('lab_code', function ($q) use ($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) {
                $q->select('lab_code')
                    ->from('surveillance_cases')
                    ->where('surveillance_id', $surveillanceId)
                    ->whereRaw("(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek])
                    ->whereRaw("(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek]);
            })

            ->where('case_lab_results.is_positive', 1)

            ->selectRaw("
                CASE
                    WHEN LOWER(case_lab_results.pathogen_name) LIKE '%influenza%'
                        THEN 'Influenza'
                    ELSE case_lab_results.pathogen_name
                END as pathogen,

                COUNT(DISTINCT case_lab_results.lab_code) as total
            ")

            ->groupBy('pathogen')
            ->havingRaw("pathogen IS NOT NULL AND pathogen != ''")
            ->orderByDesc('total')
            ->get();

        return $rows->map(function ($r) use ($total) {
            $r->rate = $total > 0 ? round(($r->total / $total) * 100, 1) : 0;
            return $r;
        });
    }
    public function subtypeDistribution($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {
        $total = $this->totalTested($surveillanceId, $startYear, $startWeek, $endYear, $endWeek);

        $rows = CaseLabResult::where('case_lab_results.surveillance_id', $surveillanceId)

            ->whereIn('case_lab_results.lab_code', function ($q) use ($surveillanceId, $startYear, $startWeek, $endYear, $endWeek) {
                $q->select('lab_code')
                    ->from('surveillance_cases')
                    ->where('surveillance_id', $surveillanceId)
                    ->whereRaw("(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek])
                    ->whereRaw("(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek]);
            })

            ->where('case_lab_results.is_positive', 1)
            ->where('case_lab_results.indicator', 'Influenza')

            ->selectRaw("
                case_lab_results.subtype as subtype,
                COUNT(DISTINCT case_lab_results.lab_code) as total
            ")


            ->groupBy('subtype')
            ->orderByDesc('total')
            ->get();

        return $rows->map(function ($r) use ($total) {
            $r->rate = $total > 0 ? round(($r->total / $total) * 100, 1) : 0;
            return $r;
        });
    }

    /*
    |--------------------------------------------------------------------------
    | Age Distribution
    |--------------------------------------------------------------------------
    */

    public function ageDistribution($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {
        return SurveillanceCase::selectRaw("
                CASE
                    WHEN patient_age_inday <= 28 THEN '0–28 days'
                    WHEN patient_age_inday <= 364 THEN '29 days–11 months'
                    WHEN patient_age_inday <= 1460 THEN '1–4 years'
                    WHEN patient_age_inday <= 5110 THEN '5–14 years'
                    WHEN patient_age_inday <= 8765 THEN '15–24 years'
                    WHEN patient_age_inday <= 18250 THEN '25–49 years'
                    WHEN patient_age_inday <= 23725 THEN '50–64 years'
                    ELSE '65+ years'
                END as age_group,

                CASE
                    WHEN patient_age_inday <= 28 THEN 1
                    WHEN patient_age_inday <= 364 THEN 2
                    WHEN patient_age_inday <= 1460 THEN 3
                    WHEN patient_age_inday <= 5110 THEN 4
                    WHEN patient_age_inday <= 8765 THEN 5
                    WHEN patient_age_inday <= 18250 THEN 6
                    WHEN patient_age_inday <= 23725 THEN 7
                    ELSE 8
                END as age_order,

                COUNT(*) as total
            ")

            ->where('surveillance_id', $surveillanceId)

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {

                $q->whereRaw(
                    "(year_data > ? OR (year_data = ? AND week_data >= ?))",
                    [$startYear, $startYear, $startWeek]
                )
                    ->whereRaw(
                        "(year_data < ? OR (year_data = ? AND week_data <= ?))",
                        [$endYear, $endYear, $endWeek]
                    );

            })

            ->groupBy('age_group', 'age_order')
            ->orderBy('age_order')
            ->get();
    }

    /*
    |--------------------------------------------------------------------------
    | Sex Distribution
    |--------------------------------------------------------------------------
    */

    public function sexDistribution($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {

        return SurveillanceCase::selectRaw("
            patient_sex,
            COUNT(*) as total
            ")

            ->where('surveillance_id', $surveillanceId)

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {

                $q->whereRaw(
                    "(year_data > ? OR (year_data = ? AND week_data >= ?))",
                    [$startYear, $startYear, $startWeek]
                )

                    ->whereRaw(
                        "(year_data < ? OR (year_data = ? AND week_data <= ?))",
                        [$endYear, $endYear, $endWeek]
                    );

            })

            ->groupBy('patient_sex')
            ->get();

    }
    /*
    |--------------------------------------------------------------------------
    | sequencing trend
    |--------------------------------------------------------------------------
    */


    public function sequencingTrend($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {
        return CaseLabResult::join(
            'surveillance_cases',
            'case_lab_results.lab_code',
            '=',
            'surveillance_cases.lab_code'
        )
            ->where('surveillance_cases.surveillance_id', $surveillanceId)

            ->where('case_lab_results.is_positive', 1)

            ->whereNotNull('subtype')

            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
                $q->whereRaw("(year_data > ? OR (year_data = ? AND week_data >= ?))", [$startYear, $startYear, $startWeek])
                    ->whereRaw("(year_data < ? OR (year_data = ? AND week_data <= ?))", [$endYear, $endYear, $endWeek]);
            })

            ->selectRaw("
                concat(surveillance_cases.year_data,'-',surveillance_cases.week_data) as period,
                subtype,
                COUNT(DISTINCT surveillance_cases.lab_code) as total
            ")

            ->groupBy('period', 'subtype')
            ->orderBy('period')
            ->get();
    }


    public function influenzaRelativeOverTimeSequencing($startYear, $startWeek, $endYear, $endWeek)
    {
        return SurveillanceCase::join('case_lab_results', function ($join) {
            $join->on('surveillance_cases.lab_code', '=', 'case_lab_results.lab_code')
                ->on('surveillance_cases.surveillance_id', '=', 'case_lab_results.surveillance_id');
        })
            ->where(function ($q) use ($startYear, $startWeek, $endYear, $endWeek) {
                $q->whereRaw(
                    "(surveillance_cases.year_data * 100 + surveillance_cases.week_data) BETWEEN ? AND ?",
                    [
                        $startYear * 100 + $startWeek,
                        $endYear * 100 + $endWeek
                    ]
                );
            })
            ->whereRaw('case_lab_results.is_positive = 1 and surveillance_cases.surveillance_id in(6) and case_lab_results.indicator="Influenza"')
            ->selectRaw("
                case_lab_results.pathogen_name as lineage,
                concat(surveillance_cases.year_data,'-',surveillance_cases.week_data) as week,
                COUNT(DISTINCT surveillance_cases.lab_code) as total
            ")
            ->groupBy(
                'case_lab_results.pathogen_name',
                'week'
            )
            ->get();
    }


    public function programDashboardData($surveillanceId, $startYear, $startWeek, $endYear, $endWeek)
    {

        return [

            'total_tested' => $this->totalTested(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),

            'summary' => $this->programSummary(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),

            'trend' => $this->trendSingleProgram(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),

            'pathogen_distribution' => $this->pathogenDistribution(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),

            'age_distribution' => $this->ageDistribution(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),

            'sex_distribution' => $this->sexDistribution(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),
            // 'afi_trend' => $this->afiTrend(
            //     $surveillanceId,
            //     $startYear,
            //     $startWeek,
            //     $endYear,
            //     $endWeek
            // ),
            'afi_case_trend' => $this->afiCaseTrend(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),

            'province_distribution' => $this->provinceProgram(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),
            'virus_trend' => $this->virusTrend(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),
            'subtype_distribution' => $this->subtypeDistribution(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),
            'sentinel_sites' => $this->sentinelSites(
                $surveillanceId,
                $startYear,
                $startWeek,
                $endYear,
                $endWeek
            ),

        ];

    }

}
