<?php
namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Models\EnvironmentalMonitoring;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

/** Live data for the Command Centre — Environmental Management module (EPA monitoring). */
class EnvController extends Controller
{
    use Concerns\DashboardHelpers;

    public function show(Request $r)
    {
        $this->need('hse.view');
        $qry = $r->get('qry', 'all');
        [$cf, $ct, $pf, $pt, $grain] = $this->windows((string) $r->get('period', 'This Month'));

        $monQ = fn() => EnvironmentalMonitoring::when($qry !== 'all', fn($q) => $q->where('quarry_id', $qry));
        $reads = (clone $monQ())->whereBetween('monitoring_date', [$cf, $ct])->count();
        $readsP = (clone $monQ())->whereBetween('monitoring_date', [$pf, $pt])->count();
        $breach = (clone $monQ())->whereBetween('monitoring_date', [$cf, $ct])->where('compliant', false)->count();
        $breachP = (clone $monQ())->whereBetween('monitoring_date', [$pf, $pt])->where('compliant', false)->count();
        $comp = $reads > 0 ? round(($reads - $breach) / $reads * 100, 1) : 100;
        $compP = $readsP > 0 ? round(($readsP - $breachP) / $readsP * 100, 1) : 100;
        $params = (clone $monQ())->whereBetween('monitoring_date', [$cf, $ct])->distinct('parameter')->count('parameter');
        $points = (clone $monQ())->whereBetween('monitoring_date', [$cf, $ct])->distinct('location_point')->count('location_point');
        $sites = (clone $monQ())->whereBetween('monitoring_date', [$cf, $ct])->distinct('quarry_id')->count('quarry_id');

        $ratios = (clone $monQ())->whereBetween('monitoring_date', [$cf, $ct])->where('permissible_limit', '>', 0)
            ->selectRaw('max(reading_value/permissible_limit*100) mx, avg(reading_value/permissible_limit*100) av')->first();
        $worst = round((float) $ratios->mx, 1);
        $avg = round((float) $ratios->av, 1);

        $dust = (clone $monQ())->where('parameter', 'dust-pm10')->orderByDesc('monitoring_date')->orderByDesc('id')->first();
        $noise = (clone $monQ())->where('parameter', 'noise')->orderByDesc('monitoring_date')->orderByDesc('id')->first();

        $lastRead = (clone $monQ())->max('monitoring_date');
        $stale = $lastRead ? Carbon::parse($lastRead)->diffInDays(Carbon::today()) : 0;

        $wkf = Carbon::today()->subDays(6)->format('Y-m-d');
        $wkt = Carbon::today()->format('Y-m-d');
        $wkp1 = Carbon::today()->subDays(13)->format('Y-m-d');
        $wkp0 = Carbon::today()->subDays(7)->format('Y-m-d');
        $wk = (clone $monQ())->whereBetween('monitoring_date', [$wkf, $wkt])->count();
        $wkP = (clone $monQ())->whereBetween('monitoring_date', [$wkp1, $wkp0])->count();

        $cards = [
            $this->card('Monitoring Readings', $reads, '#', $readsP),
            $this->card('Compliance Rate', $comp, '%', $compP, [], ['tgt' => 100]),
            $this->card('Non-Compliant Readings', $breach, '#', $breachP, [], ['good' => 'down', 'st' => $breach > 0 ? 'red' : 'green']),
            $this->card('Parameters Monitored', $params, '#', $params, [], ['st' => 'blue']),
            $this->card('Monitoring Points', $points, '#', $points, [], ['st' => 'blue']),
            $this->card('Worst Reading (% of limit)', $worst, '%', $worst, [], ['good' => 'down', 'tgt' => 100]),
            $this->card('Avg Reading (% of limit)', $avg, '%', $avg, [], ['good' => 'down']),
            $this->card('Dust PM10 — latest', $dust ? round((float) $dust->reading_value, 1) : 0, 'num', $dust ? round((float) $dust->reading_value, 1) : 0, [], ['info' => $dust ? ($dust->unit . ', limit ' . $dust->permissible_limit) : 'no readings']),
            $this->card('Noise — latest', $noise ? round((float) $noise->reading_value, 1) : 0, 'num', $noise ? round((float) $noise->reading_value, 1) : 0, [], ['info' => $noise ? ($noise->unit . ', limit ' . $noise->permissible_limit) : 'no readings']),
            $this->card('Days Since Last Reading', $stale, 'num', $stale, [], ['good' => 'down', 'st' => $stale > 7 ? 'amber' : 'green']),
            $this->card('Quarries Monitored', $sites, '#', $sites, [], ['st' => 'blue']),
            $this->card('Readings This Week', $wk, '#', $wkP),
        ];

        return response()->json([
            'sub' => 'EPA monitoring · compliance · dust · noise · water · ' . $r->get('period', 'This Month'),
            'asAt' => Carbon::today()->format('d M Y'),
            'cards' => $cards,
            'sections' => [
                $this->secTrend($qry),
                $this->secDust($qry),
                $this->secComp($qry, $cf, $ct),
                $this->secByParam($qry, $cf, $ct),
                $this->secReadings($qry),
                $this->secBreach($qry),
            ],
        ]);
    }

    private function secTrend($qry): array
    {
        $t = Carbon::today();
        $tot = [];
        $bad = [];
        for ($i = 29; $i >= 0; $i--) {
            $d = $t->copy()->subDays($i)->format('Y-m-d');
            $tot[] = EnvironmentalMonitoring::when($qry !== 'all', fn($q) => $q->where('quarry_id', $qry))->whereDate('monitoring_date', $d)->count();
            $bad[] = EnvironmentalMonitoring::when($qry !== 'all', fn($q) => $q->where('quarry_id', $qry))->whereDate('monitoring_date', $d)->where('compliant', false)->count();
        }
        return ['k' => 'chart', 'id' => 'e_trend', 'ti' => 'Readings vs Breaches — per day (30 days)', 'cls' => 'wide', 'spec' => [
            'type' => 'line', 'fmt' => 'num', 'zoom' => true, 'height' => 280,
            'labels' => $this->dailyLabels(30),
            'series' => [
                ['name' => 'Readings', 'data' => $tot, 'color' => '#22c55e', 'area' => true],
                ['name' => 'Breaches', 'data' => $bad, 'color' => '#ef4444'],
            ],
        ]];
    }

    private function secDust($qry): array
    {
        $rows = EnvironmentalMonitoring::when($qry !== 'all', fn($q) => $q->where('quarry_id', $qry))
            ->where('parameter', 'dust-pm10')->orderBy('monitoring_date')->orderBy('id')->take(12)->get();
        $labels = $rows->map(fn($m) => Carbon::parse($m->monitoring_date)->format('d M'))->all();
        $data = $rows->map(fn($m) => round((float) $m->reading_value, 1))->all();
        $limit = $rows->count() ? round((float) $rows->first()->permissible_limit, 1) : 0;
        return ['k' => 'chart', 'id' => 'e_dust', 'ti' => 'Dust PM10 — readings vs EPA limit (last 12)', 'cls' => 'wide', 'spec' => [
            'type' => 'line', 'fmt' => 'num', 'zoom' => true, 'height' => 260,
            'labels' => $labels,
            'series' => [['name' => 'PM10', 'data' => $data, 'color' => '#f97316', 'area' => true]],
            'target' => ['value' => $limit, 'label' => 'EPA limit'],
        ]];
    }

    private function secComp($qry, $cf, $ct): array
    {
        $tot = EnvironmentalMonitoring::when($qry !== 'all', fn($q) => $q->where('quarry_id', $qry))->whereBetween('monitoring_date', [$cf, $ct])->count();
        $bad = EnvironmentalMonitoring::when($qry !== 'all', fn($q) => $q->where('quarry_id', $qry))->whereBetween('monitoring_date', [$cf, $ct])->where('compliant', false)->count();
        $items = [
            ['label' => 'Compliant', 'value' => $tot - $bad, 'color' => '#22c55e'],
            ['label' => 'Breach', 'value' => $bad, 'color' => '#ef4444'],
        ];
        return ['k' => 'chart', 'id' => 'e_comp', 'ti' => 'Compliance Split — readings (period)', 'spec' => [
            'type' => 'doughnut', 'fmt' => 'num', 'center' => 'EPA', 'items' => $items,
        ]];
    }

    private function secByParam($qry, $cf, $ct): array
    {
        $rows = EnvironmentalMonitoring::when($qry !== 'all', fn($q) => $q->where('quarry_id', $qry))
            ->whereBetween('monitoring_date', [$cf, $ct])->where('permissible_limit', '>', 0)
            ->select('parameter', DB::raw('avg(reading_value/permissible_limit*100) t'))->groupBy('parameter')->orderByDesc('t')->get();
        return ['k' => 'chart', 'id' => 'e_byparam', 'ti' => 'Avg Reading by Parameter — % of limit (period)', 'spec' => [
            'type' => 'hbar', 'fmt' => 'pct',
            'labels' => $rows->map(fn($r) => ucwords(str_replace('-', ' ', (string) $r->parameter)))->all(),
            'series' => [['name' => '%', 'data' => $rows->map(fn($r) => round((float) $r->t, 1))->all(), 'color' => '#3b82f6']],
        ]];
    }

    private function secReadings($qry): array
    {
        $rows = EnvironmentalMonitoring::with('quarry')
            ->when($qry !== 'all', fn($q) => $q->where('quarry_id', $qry))
            ->orderByDesc('monitoring_date')->orderByDesc('id')->take(60)->get()
            ->map(fn($m) => ['date' => substr((string) $m->monitoring_date, 0, 10), 'site' => $m->quarry->name ?? '',
                'param' => ucwords(str_replace('-', ' ', (string) $m->parameter)),
                'read' => round((float) $m->reading_value, 2), 'unit' => $m->unit ?? '',
                'limit' => round((float) $m->permissible_limit, 2),
                'pct' => $m->permissible_limit > 0 ? round($m->reading_value / $m->permissible_limit * 100, 1) . '%' : '—',
                'point' => $m->location_point ?? '', 'by' => $m->monitored_by ?? '',
                'st' => $m->compliant ? 'green' : 'red', 'stL' => $m->compliant ? 'Compliant' : 'Breach'])->all();
        return ['k' => 'table', 'id' => 'e_read', 'ti' => 'Monitoring Register — latest 60', 'cls' => 'wide', 'cfg' => [
            'id' => 'e_read', 'page' => 12, 'search' => true,
            'cols' => [
                ['k' => 'date', 'l' => 'Date'], ['k' => 'site', 'l' => 'Site'], ['k' => 'param', 'l' => 'Parameter', 'wide' => 1],
                ['k' => 'read', 'l' => 'Reading', 'y' => 'num'], ['k' => 'unit', 'l' => 'Unit'],
                ['k' => 'limit', 'l' => 'Limit', 'y' => 'num'], ['k' => 'pct', 'l' => '% of limit'],
                ['k' => 'point', 'l' => 'Point'], ['k' => 'by', 'l' => 'Monitored by'], ['k' => 'st', 'l' => 'Status', 'y' => 'badge'],
            ], 'rows' => $rows, 'totals' => [],
        ]];
    }

    private function secBreach($qry): array
    {
        $rows = EnvironmentalMonitoring::with('quarry')
            ->when($qry !== 'all', fn($q) => $q->where('quarry_id', $qry))->where('compliant', false)
            ->orderByDesc('monitoring_date')->take(30)->get()
            ->map(fn($m) => ['date' => substr((string) $m->monitoring_date, 0, 10), 'site' => $m->quarry->name ?? '',
                'param' => ucwords(str_replace('-', ' ', (string) $m->parameter)),
                'read' => round((float) $m->reading_value, 2), 'limit' => round((float) $m->permissible_limit, 2),
                'pct' => $m->permissible_limit > 0 ? round($m->reading_value / $m->permissible_limit * 100, 1) . '%' : '—',
                'point' => $m->location_point ?? '', 'rem' => mb_strimwidth((string) $m->remarks, 0, 60, '…'),
                'st' => 'red', 'stL' => 'Breach'])->all();
        return ['k' => 'table', 'id' => 'e_breach', 'ti' => 'Limit Breaches — latest 30', 'cls' => 'wide', 'cfg' => [
            'id' => 'e_breach', 'page' => 10, 'search' => true,
            'cols' => [
                ['k' => 'date', 'l' => 'Date'], ['k' => 'site', 'l' => 'Site'], ['k' => 'param', 'l' => 'Parameter', 'wide' => 1],
                ['k' => 'read', 'l' => 'Reading', 'y' => 'num'], ['k' => 'limit', 'l' => 'Limit', 'y' => 'num'],
                ['k' => 'pct', 'l' => '% of limit'], ['k' => 'point', 'l' => 'Point'], ['k' => 'rem', 'l' => 'Remarks'],
                ['k' => 'st', 'l' => 'Status', 'y' => 'badge'],
            ], 'rows' => $rows, 'totals' => [],
        ]];
    }
}
