<?php

namespace App\Http\Controllers;

use App\Models\Order;
use App\Models\OrderItem;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class ProductionController extends Controller
{
    public function index(Request $request)
    {
        $viewMode = $request->get('mode', 'per_item');
        $search   = $request->get('search');

        $category = $request->get('category', 'all');
        $allowedCategories = ['all', 'versant', 'indoor', 'outdoor'];
        if (!in_array($category, $allowedCategories, true)) {
            $category = 'all';
        }

        $orderSearch = function ($query) use ($search) {
            if (!$search) return;

            $query->where(function ($q) use ($search) {
                $q->where('invoice_number', 'like', "%{$search}%")
                    ->orWhere('customer_name', 'like', "%{$search}%")
                    ->orWhere('notes', 'like', "%{$search}%")
                    ->orWhereHas('items', function ($iq) use ($search) {
                        $iq->where('file_name', 'like', "%{$search}%")
                            ->orWhere('product_name', 'like', "%{$search}%")
                            ->orWhere('material_name', 'like', "%{$search}%")
                            ->orWhere('finishing_note', 'like', "%{$search}%");
                    });
            });
        };

        $orderCategoryFilter = function ($query) use ($category) {
            if ($category === 'all') return;

            $query->whereHas('activeItems', function ($qi) use ($category) {
                $qi->where('product_name', 'like', '%' . $category . '%');
            });
        };

        $itemSearch = function ($query) use ($search) {
            if (!$search) return;

            $query->where(function ($q) use ($search) {
                $q->where('file_name', 'like', "%{$search}%")
                    ->orWhere('product_name', 'like', "%{$search}%")
                    ->orWhere('material_name', 'like', "%{$search}%")
                    ->orWhere('finishing_note', 'like', "%{$search}%")
                    ->orWhereHas('order', function ($oq) use ($search) {
                        $oq->where('invoice_number', 'like', "%{$search}%")
                            ->orWhere('customer_name', 'like', "%{$search}%");
                    });
            });
        };

        $itemCategoryFilter = function ($query) use ($category) {
            if ($category === 'all') return;
            $query->where('product_name', 'like', '%' . $category . '%');
        };

        $pendingOrders = Order::with(['designer', 'activeItems'])
            ->notCancelled()
            ->paid()
            ->pending()
            ->tap($orderCategoryFilter)
            ->tap($orderSearch)
            ->oldest()
            ->get();

        $prosesOrders = Order::with(['designer', 'operator', 'activeItems'])
            ->notCancelled()
            ->where('production_status', Order::STATUS_PROSES_CETAK)
            ->tap($orderCategoryFilter)
            ->tap($orderSearch)
            ->oldest('started_at')
            ->get();

        $completedOrders = Order::with(['designer', 'operator', 'finishingOperator', 'activeItems'])
            ->notCancelled()
            ->completed()
            ->whereDate('finished_at', today())
            ->tap($orderCategoryFilter)
            ->tap($orderSearch)
            ->latest('finished_at')
            ->take(10)
            ->get();

        $data = [
            'title' => 'Produksi',
            'viewMode' => $viewMode,
            'search' => $search,
            'category' => $category,
            'pendingOrders' => $pendingOrders,
            'prosesOrders' => $prosesOrders,
            'completedOrders' => $completedOrders,
        ];

        if ($viewMode === 'per_item') {
            $data['pendingItems'] = OrderItem::with(['order'])
                ->where('is_cancelled', false)
                ->whereHas('order', fn ($q) => $q->notCancelled()->where(function ($q2) {
                    $q2->where('payment_status', Order::PAYMENT_PAID)
                        ->orWhere('is_credit', true);
                }))
                ->where('production_status', OrderItem::STATUS_PENDING)
                ->tap($itemCategoryFilter)
                ->tap($itemSearch)
                ->oldest()
                ->get();

            $data['prosesItems'] = OrderItem::with(['order'])
                ->where('is_cancelled', false)
                ->where('production_status', OrderItem::STATUS_PROSES_CETAK)
                ->tap($itemCategoryFilter)
                ->tap($itemSearch)
                ->oldest('item_started_at')
                ->get();

            $data['completedItems'] = OrderItem::with(['order'])
                ->where('is_cancelled', false)
                ->where('production_status', OrderItem::STATUS_SELESAI)
                ->whereDate('item_finished_at', today())
                ->tap($itemCategoryFilter)
                ->tap($itemSearch)
                ->latest('item_finished_at')
                ->take(20)
                ->get();
        }

        return view('pages.produksi.index', $data);
    }

    public function show(Order $order)
    {
        $order->load(['designer', 'cashier', 'operator', 'finishingOperator', 'items']);

        return view('pages.produksi.show', [
            'title' => 'Detail Produksi #' . $order->invoice_number,
            'order' => $order,
        ]);
    }

    public function startProduction(Request $request, Order $order)
    {
        if (!$order->canStartProduction()) {
            return back()->with('error', 'Order tidak dapat dimulai produksi.');
        }

        $order->startProduction($request->user());

        return back()->with('success', 'Produksi dimulai untuk order #' . $order->invoice_number);
    }

    public function moveToFinishing(Order $order)
    {
        if (!$order->canMoveToFinishing()) {
            return back()->with('error', 'Order tidak dapat dipindahkan ke finishing.');
        }

        $order->moveToFinishing();

        return back()->with('success', 'Order #' . $order->invoice_number . ' dipindahkan ke finishing.');
    }

    public function markComplete(Order $order)
    {
        if (!$order->canMarkComplete()) {
            return back()->with('error', 'Order tidak dapat diselesaikan.');
        }

        $order->markAsComplete();

        return back()->with('success', 'Order #' . $order->invoice_number . ' selesai!');
    }

    public function revertToPending(Order $order)
    {
        if (!$order->canRevertToPending()) {
            return back()->with('error', 'Order tidak dapat dikembalikan ke antrian.');
        }

        $order->revertToPending();

        return back()->with('success', 'Order #' . $order->invoice_number . ' dikembalikan ke antrian.');
    }

    public function revertToProsesCetak(Order $order)
    {
        if (!$order->canRevertToProsesCetak()) {
            return back()->with('error', 'Order tidak dapat dikembalikan ke proses cetak.');
        }

        $order->revertToProsesCetak();

        return back()->with('success', 'Order #' . $order->invoice_number . ' dikembalikan ke proses cetak.');
    }

    public function startItemProduction(Request $request, OrderItem $orderItem)
    {
        if (!$orderItem->canStartItemProduction()) {
            return back()->with('error', 'Item tidak dapat dimulai produksi.');
        }

        $orderItem->startProduction();

        return back()->with('success', 'Produksi dimulai untuk item "' . $orderItem->file_name . '"');
    }

    public function moveItemToFinishing(OrderItem $orderItem)
    {
        if (!$orderItem->canMoveItemToFinishing()) {
            return back()->with('error', 'Item tidak dapat dipindahkan ke finishing.');
        }

        $orderItem->moveToFinishing();

        return back()->with('success', 'Item "' . $orderItem->file_name . '" dipindahkan ke finishing.');
    }

    public function markItemComplete(OrderItem $orderItem)
    {
        if (!$orderItem->canMarkItemComplete()) {
            return back()->with('error', 'Item tidak dapat diselesaikan.');
        }

        $orderItem->markAsComplete();

        return back()->with('success', 'Item "' . $orderItem->file_name . '" selesai!');
    }

    public function revertItemToPending(OrderItem $orderItem)
    {
        if (!$orderItem->canRevertItemToPending()) {
            return back()->with('error', 'Item tidak dapat dikembalikan ke antrian.');
        }

        $orderItem->revertToPending();

        return back()->with('success', 'Item "' . $orderItem->file_name . '" dikembalikan ke antrian.');
    }

    public function revertItemToProsesCetak(OrderItem $orderItem)
    {
        if (!$orderItem->canRevertToProsesCetak()) {
            return back()->with('error', 'Item tidak dapat dikembalikan ke proses cetak.');
        }

        $orderItem->revertToProsesCetak();

        return back()->with('success', 'Item "' . $orderItem->file_name . '" dikembalikan ke proses cetak.');
    }

    public function history(Request $request)
    {
        $applyHistoryFilters = function ($query) use ($request) {
            if ($request->filled('date')) {
                $date = $request->date;

                $query->where(function ($q) use ($date) {
                    $q->whereDate('finished_at', $date)
                        ->orWhereDate('started_at', $date)
                        ->orWhereDate('created_at', $date);
                });
            }

            if ($request->filled('pickup')) {
                $query->where('pickup_status', $request->pickup);
            }

            if ($request->filled('production_stage')) {
                $stage = $request->production_stage;

                $query->where(function ($q) use ($stage) {
                    if ($stage === 'waiting') {
                        $q->where(function ($sq) {
                            $sq->whereNull('production_status')
                                ->orWhere('production_status', Order::STATUS_PENDING);
                        });
                    } elseif ($stage === 'design') {
                        $q->where(function ($sq) {
                            $sq->where('production_status', 'like', '%design%')
                                ->orWhere('production_status', 'like', '%desain%');
                        });
                    } elseif ($stage === 'printing') {
                        $q->where('production_status', Order::STATUS_PROSES_CETAK);
                    } elseif ($stage === 'finishing') {
                        $q->where('production_status', Order::STATUS_FINISHING);
                    } elseif ($stage === 'finished') {
                        $q->completed()
                            ->where(function ($sq) {
                                $sq->whereNull('pickup_status')
                                    ->orWhere('pickup_status', '!=', 'picked_up');
                            });
                    } elseif ($stage === 'picked_up') {
                        $q->where('pickup_status', 'picked_up');
                    }
                });
            }

            if ($request->filled('designer_id')) {
                $query->where('designer_id', $request->designer_id);
            }

            if ($request->filled('operator_id')) {
                $query->where('operator_id', $request->operator_id);
            }

            if ($request->filled('finishing_operator_id')) {
                $query->where('finishing_operator_id', $request->finishing_operator_id);
            }

            if ($request->filled('search')) {
                $search = trim($request->search);

                $query->where(function ($q) use ($search) {
                    $q->where('invoice_number', 'like', "%{$search}%")
                        ->orWhere('customer_name', 'like', "%{$search}%")
                        ->orWhereHas('items', function ($itemQuery) use ($search) {
                            $itemQuery->where('file_name', 'like', "%{$search}%")
                                ->orWhere('product_name', 'like', "%{$search}%")
                                ->orWhere('material_name', 'like', "%{$search}%")
                                ->orWhere('finishing_note', 'like', "%{$search}%");
                        });
                });
            }

            return $query;
        };

        $baseQuery = Order::query()
            ->with([
                'items',
                'designer:id,name',
                'operator:id,name',
                'finishingOperator:id,name',
            ])
            ->notCancelled()
            ->where(function ($q) {
                $q->whereIn('production_status', [
                    Order::STATUS_PENDING,
                    Order::STATUS_PROSES_CETAK,
                    Order::STATUS_FINISHING,
                    Order::STATUS_SELESAI,
                ])
                ->orWhereNotNull('started_at')
                ->orWhereNotNull('finished_at')
                ->orWhere('pickup_status', 'picked_up');
            });

        $applyHistoryFilters($baseQuery);

        $orders = (clone $baseQuery)
            ->orderByRaw('COALESCE(finished_at, started_at, created_at) DESC')
            ->paginate(15)
            ->withQueryString();

        $summaryBase = Order::query()
            ->notCancelled()
            ->where(function ($q) {
                $q->whereIn('production_status', [
                    Order::STATUS_PENDING,
                    Order::STATUS_PROSES_CETAK,
                    Order::STATUS_FINISHING,
                    Order::STATUS_SELESAI,
                ])
                ->orWhereNotNull('started_at')
                ->orWhereNotNull('finished_at')
                ->orWhere('pickup_status', 'picked_up');
            });

        $applyHistoryFilters($summaryBase);

        $avgDurationMinutes = (clone $summaryBase)
            ->whereNotNull('started_at')
            ->whereNotNull('finished_at')
            ->selectRaw('AVG(TIMESTAMPDIFF(MINUTE, started_at, finished_at)) as avg_minutes')
            ->value('avg_minutes');

        $summary = [
            'total_finished' => (clone $summaryBase)->count(),
            'total_picked_up' => (clone $summaryBase)->where('pickup_status', 'picked_up')->count(),
            'today_finished' => (clone $summaryBase)->whereDate('finished_at', today())->count(),
            'avg_duration_text' => $this->formatMinutes($avgDurationMinutes),
            'total_waiting' => (clone $summaryBase)->where(function ($q) {
                $q->whereNull('production_status')
                    ->orWhere('production_status', Order::STATUS_PENDING);
            })->count(),
            'total_printing' => (clone $summaryBase)->where('production_status', Order::STATUS_PROSES_CETAK)->count(),
            'total_finishing' => (clone $summaryBase)->where('production_status', Order::STATUS_FINISHING)->count(),
        ];

        $todayDate = now()->toDateString();
        $currentYear = now()->year;
        $currentMonth = now()->month;

        $performanceBase = Order::query()
            ->from('orders')
            ->leftJoin('users as operator_users', 'orders.operator_id', '=', 'operator_users.id')
            ->completed()
            ->whereNotNull('orders.operator_id');

        if ($request->filled('date')) {
            $performanceBase->whereDate('orders.finished_at', $request->date);
        }

        if ($request->filled('pickup')) {
            $performanceBase->where('orders.pickup_status', $request->pickup);
        }

        if ($request->filled('designer_id')) {
            $performanceBase->where('orders.designer_id', $request->designer_id);
        }

        if ($request->filled('operator_id')) {
            $performanceBase->where('orders.operator_id', $request->operator_id);
        }

        if ($request->filled('finishing_operator_id')) {
            $performanceBase->where('orders.finishing_operator_id', $request->finishing_operator_id);
        }

        if ($request->filled('search')) {
            $search = trim($request->search);

            $performanceBase->where(function ($q) use ($search) {
                $q->where('orders.invoice_number', 'like', "%{$search}%")
                    ->orWhere('orders.customer_name', 'like', "%{$search}%")
                    ->orWhereExists(function ($sub) use ($search) {
                        $sub->select(DB::raw(1))
                            ->from('order_items')
                            ->whereColumn('order_items.order_id', 'orders.id')
                            ->where(function ($itemQuery) use ($search) {
                                $itemQuery->where('order_items.file_name', 'like', "%{$search}%")
                                    ->orWhere('order_items.product_name', 'like', "%{$search}%")
                                    ->orWhere('order_items.material_name', 'like', "%{$search}%")
                                    ->orWhere('order_items.finishing_note', 'like', "%{$search}%");
                            });
                    });
            });
        }

        $performanceStats = (clone $performanceBase)
            ->selectRaw("
                orders.operator_id,
                COALESCE(operator_users.name, '-') as name,
                SUM(CASE WHEN DATE(orders.finished_at) = ? THEN 1 ELSE 0 END) as today_count,
                SUM(CASE WHEN YEAR(orders.finished_at) = ? AND MONTH(orders.finished_at) = ? THEN 1 ELSE 0 END) as month_count,
                COUNT(*) as total_count,
                AVG(
                    CASE
                        WHEN orders.started_at IS NOT NULL AND orders.finished_at IS NOT NULL
                        THEN TIMESTAMPDIFF(MINUTE, orders.started_at, orders.finished_at)
                        ELSE NULL
                    END
                ) as avg_duration_minutes
            ", [$todayDate, $currentYear, $currentMonth])
            ->groupBy('orders.operator_id', 'operator_users.name')
            ->orderByDesc('month_count')
            ->orderByDesc('total_count')
            ->get()
            ->map(function ($row) {
                return [
                    'id' => $row->operator_id,
                    'name' => $row->name,
                    'today_count' => (int) $row->today_count,
                    'month_count' => (int) $row->month_count,
                    'total_count' => (int) $row->total_count,
                    'avg_duration_text' => $this->formatMinutes($row->avg_duration_minutes),
                ];
            });

        $topOperatorMonth = (clone $performanceBase)
            ->selectRaw("
                orders.operator_id,
                COALESCE(operator_users.name, '-') as name,
                SUM(CASE WHEN YEAR(orders.finished_at) = ? AND MONTH(orders.finished_at) = ? THEN 1 ELSE 0 END) as total
            ", [$currentYear, $currentMonth])
            ->groupBy('orders.operator_id', 'operator_users.name')
            ->orderByDesc('total')
            ->first();

        $topDesignerMonth = Order::query()
            ->from('orders')
            ->leftJoin('users as designer_users', 'orders.designer_id', '=', 'designer_users.id')
            ->completed()
            ->whereNotNull('orders.designer_id')
            ->whereYear('orders.finished_at', $currentYear)
            ->whereMonth('orders.finished_at', $currentMonth)
            ->selectRaw('orders.designer_id, COALESCE(designer_users.name, "-") as name, COUNT(*) as total')
            ->groupBy('orders.designer_id', 'designer_users.name')
            ->orderByDesc('total')
            ->first();

        $topFinishingMonth = Order::query()
            ->from('orders')
            ->leftJoin('users as finishing_users', 'orders.finishing_operator_id', '=', 'finishing_users.id')
            ->completed()
            ->whereNotNull('orders.finishing_operator_id')
            ->whereYear('orders.finished_at', $currentYear)
            ->whereMonth('orders.finished_at', $currentMonth)
            ->selectRaw('orders.finishing_operator_id, COALESCE(finishing_users.name, "-") as name, COUNT(*) as total')
            ->groupBy('orders.finishing_operator_id', 'finishing_users.name')
            ->orderByDesc('total')
            ->first();

        $designers = User::query()
            ->whereIn('id', Order::query()->notCancelled()->whereNotNull('designer_id')->distinct()->pluck('designer_id'))
            ->orderBy('name')
            ->get(['id', 'name']);

        $operators = User::query()
            ->whereIn('id', Order::query()->notCancelled()->whereNotNull('operator_id')->distinct()->pluck('operator_id'))
            ->orderBy('name')
            ->get(['id', 'name']);

        $finishingOperators = User::query()
            ->whereIn('id', Order::query()->notCancelled()->whereNotNull('finishing_operator_id')->distinct()->pluck('finishing_operator_id'))
            ->orderBy('name')
            ->get(['id', 'name']);

        return view('pages.produksi.history', [
            'title' => 'Riwayat & Proses Produksi',
            'orders' => $orders,
            'summary' => $summary,
            'performanceStats' => $performanceStats,
            'topOperatorMonth' => $topOperatorMonth,
            'topDesignerMonth' => $topDesignerMonth,
            'topFinishingMonth' => $topFinishingMonth,
            'designers' => $designers,
            'operators' => $operators,
            'finishingOperators' => $finishingOperators,
        ]);
    }

    private function formatMinutes($minutes): string
    {
        if (!$minutes || $minutes < 1) {
            return '< 1m';
        }

        $minutes = (int) round($minutes);
        $hours = intdiv($minutes, 60);
        $mins = $minutes % 60;

        if ($hours > 0 && $mins > 0) {
            return "{$hours}j {$mins}m";
        }

        if ($hours > 0) {
            return "{$hours}j";
        }

        return "{$mins}m";
    }
}