<?php

namespace App\Http\Controllers\Admin;

use App\Exports\SessionsExport;
use App\Exports\SessionsMonthlyExport;
use App\Http\Controllers\Controller;
use App\Mail\SessionReportMail;
use App\Models\MachinePause;
use App\Models\MachineSession;
use App\Models\User;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\Rules\Password;
use Maatwebsite\Excel\Facades\Excel;

class AdminDashboardController extends Controller
{
    public function index()
    {
        $totalOperators = User::where('role', 'operator')->count();
        $totalAdmins = User::where('role', 'admin')->count();

        $sessions = MachineSession::with('operator')
            ->withCount('segments')
            ->orderBy('created_at', 'desc')
            ->paginate(15);

        return view('admin.dashboard', compact('totalOperators', 'totalAdmins', 'sessions'));
    }

    public function sessions()
    {
        $sessions = MachineSession::with('operator')
            ->withCount('segments')
            ->orderBy('created_at', 'desc')
            ->paginate(20);

        return view('admin.sessions.index', compact('sessions'));
    }

    public function sessionDetail(MachineSession $session)
    {
        $session->load(['operator', 'pauses', 'segments']);

        // Calculate per-segment OEE
        $segmentOees = [];
        $totalExpected = 0;
        $totalCases = 0;

        foreach ($session->segments as $segment) {
            if ($segment->is_active && $session->status !== 'stopped') {
                $runSec = $this->computeSegmentRunSeconds($segment, now(), $session->pauses);
                $segmentOees[$segment->id] = $segment->calculateOee($runSec);
                $runHours = $runSec / 3600;
            } else {
                $segmentOees[$segment->id] = $segment->calculateOee();
                $runHours = $segment->run_seconds / 3600;
            }
            $totalExpected += $runHours * $segment->filling_rate;
            $totalCases += (int) $segment->case_number;
        }

        // Overall OEE: weighted across all segments by their expected output
        $oee = 0;
        if ($session->segments->count() > 0 && $totalExpected > 0 && $totalCases > 0) {
            $oee = round(($totalCases / $totalExpected) * 100, 1);
        } elseif ($session->segments->count() === 0) {
            // Fallback for sessions created before segments feature
            $actualRunSeconds = 0;
            if ($session->status === 'stopped' && $session->total_duration > 0) {
                $actualRunSeconds = $session->total_duration - $session->total_pause_duration;
            } elseif ($session->status === 'running' || $session->status === 'paused') {
                $elapsed = now()->diffInSeconds($session->start_time);
                $actualRunSeconds = max(0, $elapsed - $session->total_pause_duration);
            }
            $actualRunHours = $actualRunSeconds / 3600;
            $caseNumber = (int) $session->case_number;
            $expectedOutput = $actualRunHours * $session->filling_rate;
            if ($caseNumber > 0 && $expectedOutput > 0) {
                $oee = round(($caseNumber / $expectedOutput) * 100, 1);
            }
        }

        // Get active segment OEE and data for initial render
        $activeSegment = $session->segments->where('is_active', true)->first();
        $activeSegmentOee = 0;
        $activeSegmentRunTime = '0:00';
        if ($activeSegment && $session->status !== 'stopped') {
            $activeRunSec = $this->computeSegmentRunSeconds($activeSegment, now(), $session->pauses);
            $activeSegmentOee = $activeSegment->calculateOee($activeRunSec);
            $activeSegmentRunTime = gmdate('H:i:s', $activeRunSec);
        } elseif ($activeSegment) {
            $activeSegmentOee = $activeSegment->calculateOee();
            $activeSegmentRunTime = gmdate('H:i:s', $activeSegment->run_seconds);
        }

        // Get current pause reason if paused
        $pauseReason = null;
        if ($session->status === 'paused') {
            $openPause = $session->pauses->whereNull('resume_time')->first();
            if ($openPause) {
                $pauseReason = $openPause->pause_reason;
            }
        }

        $timeline = $this->buildRichTimeline($session);

        return view('admin.sessions.show', compact(
            'session', 'oee', 'segmentOees',
            'activeSegment', 'activeSegmentOee', 'activeSegmentRunTime', 'pauseReason',
            'timeline'
        ));
    }

    public function sessionLive(MachineSession $session)
    {
        $session->load(['pauses', 'segments']);

        $actualRunSeconds = 0;
        $pauseSeconds = $session->total_pause_duration;

        // Add current open pause duration
        $openPause = $session->pauses->whereNull('resume_time')->first();
        if ($openPause && $openPause->pause_time) {
            $pauseSeconds += now()->diffInSeconds($openPause->pause_time);
        }

        if ($session->status === 'running' || $session->status === 'paused') {
            $elapsed = now()->diffInSeconds($session->start_time);
            $actualRunSeconds = max(0, $elapsed - $pauseSeconds);
        }

        // Calculate OEE across all segments (weighted by each segment's expected output)
        $totalExpected = 0;
        $totalCases = 0;
        $activeSegment = null;
        $segRunSec = 0;

        foreach ($session->segments as $segment) {
            if ($segment->is_active) {
                $activeSegment = $segment;
                $segRunSec = $this->computeSegmentRunSeconds($segment, now(), $session->pauses);
                $runHours = $segRunSec / 3600;
            } else {
                $runHours = $segment->run_seconds / 3600;
            }
            $totalExpected += $runHours * $segment->filling_rate;
            $totalCases += (int) $segment->case_number;
        }

        $oee = 0;
        if ($totalExpected > 0 && $totalCases > 0) {
            $oee = round(($totalCases / $totalExpected) * 100, 1);
        }

        // Active segment info for display
        $segmentData = null;
        $segmentOee = 0;
        if ($activeSegment) {
            $segmentOee = $activeSegment->calculateOee($segRunSec);
            $segmentData = [
                'product_name' => $activeSegment->product_name,
                'case_number' => $activeSegment->case_number,
                'filling_rate' => $activeSegment->filling_rate,
                'oee' => $segmentOee,
                'run_time' => gmdate('H:i:s', $segRunSec),
            ];
        }

        // Get current pause reason if paused
        $pauseReason = null;
        if ($openPause && $openPause->pause_reason) {
            $pauseReason = $openPause->pause_reason;
        }

        return response()->json([
            'status' => $session->status,
            'oee' => $oee,
            'segment_oee' => $segmentOee,
            'case_number' => $session->case_number,
            'run_time' => gmdate('H:i:s', $actualRunSeconds),
            'pause_time' => gmdate('H:i:s', $pauseSeconds),
            'total_time' => gmdate('H:i:s', $actualRunSeconds + $pauseSeconds),
            'product_name' => $activeSegment ? $activeSegment->product_name : $session->product_name,
            'filling_rate' => $activeSegment ? $activeSegment->filling_rate : $session->filling_rate,
            'active_segment' => $segmentData,
            'pause_reason' => $pauseReason,
        ]);
    }

    public function sessionExport(Request $request)
    {
        $period = $request->input('period', 'monthly');

        if ($period === 'daily') {
            $validated = $request->validate(['date' => 'required|date']);
            $date  = Carbon::parse($validated['date']);
            $from  = $date->copy()->startOfDay();
            $to    = $date->copy()->endOfDay();
            $label = $date->format('d M Y');
            $file  = 'shifts_' . $date->format('Y-m-d') . '.xlsx';

        } elseif ($period === 'weekly') {
            $validated = $request->validate([
                'year' => 'required|integer|min:2020|max:2035',
                'week' => 'required|integer|min:1|max:53',
            ]);
            $from  = Carbon::now()->setISODate($validated['year'], $validated['week'])->startOfWeek();
            $to    = Carbon::now()->setISODate($validated['year'], $validated['week'])->endOfWeek();
            $label = 'Week ' . $validated['week'] . ', ' . $validated['year'];
            $file  = 'shifts_' . $validated['year'] . '_W' . str_pad($validated['week'], 2, '0', STR_PAD_LEFT) . '.xlsx';

        } else {
            $validated = $request->validate([
                'year'  => 'required|integer|min:2020|max:2035',
                'month' => 'required|integer|min:1|max:12',
            ]);
            $from  = Carbon::create($validated['year'], $validated['month'], 1)->startOfMonth();
            $to    = Carbon::create($validated['year'], $validated['month'], 1)->endOfMonth();
            $label = Carbon::create($validated['year'], $validated['month'])->format('F Y');
            $file  = 'shifts_' . $validated['year'] . '_' . str_pad($validated['month'], 2, '0', STR_PAD_LEFT) . '.xlsx';
        }

        return Excel::download(new SessionsExport($from, $to, $label), $file);
    }

    public function sessionMonthlyExport(Request $request)
    {
        $validated = $request->validate([
            'year'  => 'required|integer|min:2020|max:2035',
            'month' => 'required|integer|min:1|max:12',
        ]);

        $year     = (int) $validated['year'];
        $month    = (int) $validated['month'];
        $filename = 'shifts_' . $year . '_' . str_pad($month, 2, '0', STR_PAD_LEFT) . '.xlsx';

        return Excel::download(new SessionsMonthlyExport($year, $month), $filename);
    }

    public function sessionExportPdf(MachineSession $session)
    {
        $session->load(['operator', 'pauses', 'segments']);

        // Per-segment OEE
        $segmentOees  = [];
        $totalExpected = 0;
        $totalCases    = 0;
        foreach ($session->segments as $segment) {
            $segmentOees[$segment->id] = $segment->calculateOee();
            $runHours = $segment->run_seconds / 3600;
            $totalExpected += $runHours * $segment->filling_rate;
            $totalCases    += (int) $segment->case_number;
        }

        $oee = 0;
        if ($session->segments->count() > 0 && $totalExpected > 0 && $totalCases > 0) {
            $oee = round(($totalCases / $totalExpected) * 100, 1);
        } elseif ($session->segments->count() === 0) {
            $actualRunSeconds = 0;
            if ($session->status === 'stopped' && $session->total_duration > 0) {
                $actualRunSeconds = $session->total_duration - $session->total_pause_duration;
            }
            $actualRunHours = $actualRunSeconds / 3600;
            $caseNumber     = (int) $session->case_number;
            $expectedOutput = $actualRunHours * $session->filling_rate;
            if ($caseNumber > 0 && $expectedOutput > 0) {
                $oee = round(($caseNumber / $expectedOutput) * 100, 1);
            }
        }

        $timeline = $this->buildRichTimeline($session);

        $pdf = Pdf::loadView('admin.sessions.pdf', compact('session', 'oee', 'segmentOees', 'timeline'))
                  ->setPaper('a4', 'portrait');

        $filename = 'shift-report-' . $session->id . '-' . now()->format('Ymd') . '.pdf';
        return $pdf->download($filename);
    }

    public function sessionSendEmail(MachineSession $session)
    {
        $session->load(['operator', 'pauses', 'segments']);

        // Operator must have an email
        if (!$session->operator || !$session->operator->email) {
            return response()->json(['success' => false, 'message' => 'Operator has no email address on record.'], 422);
        }

        // Per-segment OEE
        $segmentOees   = [];
        $totalExpected = 0;
        $totalCases    = 0;
        foreach ($session->segments as $segment) {
            $segmentOees[$segment->id] = $segment->calculateOee();
            $runHours       = $segment->run_seconds / 3600;
            $totalExpected += $runHours * $segment->filling_rate;
            $totalCases    += (int) $segment->case_number;
        }
        $oee = 0;
        if ($session->segments->count() > 0 && $totalExpected > 0 && $totalCases > 0) {
            $oee = round(($totalCases / $totalExpected) * 100, 1);
        } elseif ($session->segments->count() === 0) {
            $actualRunSeconds = 0;
            if ($session->status === 'stopped' && $session->total_duration > 0) {
                $actualRunSeconds = $session->total_duration - $session->total_pause_duration;
            }
            $actualRunHours = $actualRunSeconds / 3600;
            $caseNumber     = (int) $session->case_number;
            $expectedOutput = $actualRunHours * $session->filling_rate;
            if ($caseNumber > 0 && $expectedOutput > 0) {
                $oee = round(($caseNumber / $expectedOutput) * 100, 1);
            }
        }

        $timeline = $this->buildRichTimeline($session);

        try {
            Mail::to($session->operator->email, $session->operator->name)
                ->send(new SessionReportMail($session, $oee, $segmentOees, $timeline));

            return response()->json([
                'success' => true,
                'message' => 'Report sent to ' . $session->operator->email,
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Failed to send email: ' . $e->getMessage(),
            ], 500);
        }
    }

    // ── Shared rich timeline builder (mirrors operator portal JS logic) ──
    private function buildRichTimeline(MachineSession $session): array
    {
        $segments  = $session->segments;
        $allPauses = $session->pauses->sortBy('pause_time')->values();
        $firstSeg  = $segments->first();

        // Pauses that fall within a segment's time window
        $pausesForSeg = function ($seg) use ($allPauses) {
            $sStart = $seg->started_at->timestamp;
            $sEnd   = $seg->ended_at ? $seg->ended_at->timestamp : PHP_INT_MAX;
            return $allPauses->filter(
                fn($p) => $p->pause_time && $p->pause_time->timestamp >= $sStart && $p->pause_time->timestamp < $sEnd
            )->values();
        };

        // Cases produced in a single run period within a segment
        $periodCases = function ($seg, int $periodIdx) use ($pausesForSeg) {
            $sp = $pausesForSeg($seg);
            if ($sp->isEmpty()) return $seg->case_number ?? 0;
            if ($periodIdx === 0) return $sp->first()->case_number_at_pause ?? 0;
            $prev   = $sp->get($periodIdx - 1);
            $curr   = $sp->get($periodIdx);
            $endVal = $curr ? ($curr->case_number_at_pause ?? 0) : ($seg->case_number ?? 0);
            return max(0, $endVal - ($prev->case_number_at_pause ?? 0));
        };

        $timeline = [];

        // Start event (period 0 of first segment)
        $seg0Pauses      = $firstSeg ? $pausesForSeg($firstSeg) : collect();
        $seg0FirstPause  = $seg0Pauses->first();
        $startPeriodEnd  = $seg0FirstPause ? $seg0FirstPause->pause_time
                         : ($firstSeg?->ended_at ?? Carbon::now());
        $startRunSec     = $firstSeg ? max(0, $startPeriodEnd->timestamp - $firstSeg->started_at->timestamp) : 0;

        $timeline[] = [
            'type'         => 'start',
            'time'         => $session->start_time,
            'product'      => $firstSeg ? $firstSeg->product_name : $session->product_name,
            'filling_rate' => $firstSeg ? $firstSeg->filling_rate : $session->filling_rate,
            'run_seconds'  => $startRunSec,
            'case_number'  => $firstSeg ? $periodCases($firstSeg, 0) : 0,
        ];

        // Product change events (period 0 of each subsequent segment)
        foreach ($segments as $index => $segment) {
            if ($index === 0) continue;
            $segPauses      = $pausesForSeg($segment);
            $firstPauseInSeg = $segPauses->first();
            $periodEnd      = $firstPauseInSeg ? $firstPauseInSeg->pause_time
                            : ($segment->ended_at ?? Carbon::now());
            $runSec         = max(0, $periodEnd->timestamp - $segment->started_at->timestamp);

            $timeline[] = [
                'type'         => 'product_change',
                'time'         => $segment->started_at,
                'product'      => $segment->product_name,
                'filling_rate' => $segment->filling_rate,
                'run_seconds'  => $runSec,
                'case_number'  => $periodCases($segment, 0),
            ];
        }

        // Pause and resume events
        foreach ($allPauses as $pause) {
            $timeline[] = [
                'type'     => 'pause',
                'time'     => $pause->pause_time,
                'reason'   => $pause->pause_reason,
                'duration' => $pause->duration ?? 0,
            ];

            if ($pause->resume_time) {
                $pauseTs = $pause->pause_time->timestamp;
                $seg     = $segments->first(function ($s) use ($pauseTs) {
                    $sStart = $s->started_at->timestamp;
                    $sEnd   = $s->ended_at ? $s->ended_at->timestamp : PHP_INT_MAX;
                    return $pauseTs >= $sStart && $pauseTs < $sEnd;
                }) ?? $firstSeg;

                $sp   = $seg ? $pausesForSeg($seg) : collect();
                $pIdx = $sp->search(fn($p) => $p->id === $pause->id);

                $nextPauseInSeg = ($pIdx !== false) ? $sp->get($pIdx + 1) : null;
                $periodEndTime  = $nextPauseInSeg ? $nextPauseInSeg->pause_time
                                : ($seg?->ended_at ?? Carbon::now());
                $resumeRunSec   = max(0, $periodEndTime->timestamp - $pause->resume_time->timestamp);

                $periodIdx = ($pIdx !== false) ? $pIdx + 1 : 0;
                $cases     = $seg ? $periodCases($seg, $periodIdx) : 0;

                $timeline[] = [
                    'type'        => 'resume',
                    'time'        => $pause->resume_time,
                    'duration'    => $pause->duration ?? 0,
                    'run_seconds' => $resumeRunSec,
                    'case_number' => $cases,
                    'product'     => $seg ? $seg->product_name : ($firstSeg ? $firstSeg->product_name : $session->product_name),
                ];
            }
        }

        // Stop event
        if ($session->status === 'stopped' && $session->stop_time) {
            $timeline[] = [
                'type'   => 'stop',
                'time'   => $session->stop_time,
                'reason' => $session->stop_reason,
            ];
        }

        usort($timeline, fn($a, $b) => $a['time']->timestamp <=> $b['time']->timestamp);

        return $timeline;
    }

    public function sessionDestroy(MachineSession $session)
    {
        $session->segments()->delete();
        $session->pauses()->delete();
        $session->delete();

        return redirect()->route('admin.sessions.index')->with('success', 'Session deleted successfully.');
    }

    public function profileEdit()
    {
        return view('admin.profile', ['user' => auth()->user()]);
    }

    public function profileUpdate(Request $request)
    {
        $user = auth()->user();

        $validated = $request->validate([
            'name'                  => ['required', 'string', 'max:255'],
            'email'                 => ['required', 'email', 'max:255', 'unique:users,email,' . $user->id],
            'phone'                 => ['nullable', 'string', 'max:20'],
            'current_password'      => ['nullable', 'string'],
            'password'              => ['nullable', 'confirmed', Password::min(8)],
        ]);

        // If changing password, verify current password first
        if (!empty($validated['password'])) {
            if (empty($validated['current_password']) || !Hash::check($validated['current_password'], $user->password)) {
                return back()->withErrors(['current_password' => 'Current password is incorrect.'])->withInput();
            }
        }

        $user->name  = $validated['name'];
        $user->email = $validated['email'];
        $user->phone = $validated['phone'] ?? null;

        if (!empty($validated['password'])) {
            $user->password = Hash::make($validated['password']);
        }

        $user->save();

        return back()->with('success', 'Profile updated successfully.');
    }

    private function computeSegmentRunSeconds($segment, $endTime, $pauses): int
    {
        $segStart = $segment->started_at;
        $segEnd = $segment->ended_at ?? $endTime;
        $wallSeconds = Carbon::parse($segEnd)->diffInSeconds(Carbon::parse($segStart));

        $pauseInSegment = 0;
        foreach ($pauses as $pause) {
            $pStart = $pause->pause_time;
            $pEnd = $pause->resume_time ?? $endTime;

            $overlapStart = max($pStart->timestamp, $segStart->timestamp);
            $overlapEnd = min(Carbon::parse($pEnd)->timestamp, Carbon::parse($segEnd)->timestamp);

            if ($overlapEnd > $overlapStart) {
                $pauseInSegment += ($overlapEnd - $overlapStart);
            }
        }

        return max(0, $wallSeconds - $pauseInSegment);
    }
}
