<?php

namespace App\Http\Controllers;

use App\Models\Machine;
use App\Models\Material;
use App\Models\MaterialCategory;
use App\Models\OrderItem;
use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class ClickReportController extends Controller
{
    public function index(Request $request)
    {
        $perPage = (int) $request->input('per_page', 15);

        $startDate = $request->input('start_date');
        $endDate = $request->input('end_date');
        $dateRange = $request->input('date_range', '');

        if ((!$startDate || !$endDate) && $dateRange && str_contains($dateRange, ' to ')) {
            [$rangeStart, $rangeEnd] = explode(' to ', $dateRange);
            $startDate = $startDate ?: $rangeStart;
            $endDate = $endDate ?: $rangeEnd;
        }

        $startDate = $startDate ?: now()->startOfMonth()->format('Y-m-d');
        $endDate = $endDate ?: now()->format('Y-m-d');

        $trackedProducts = Product::where('track_clicks', true)->pluck('id')->toArray();
        $trackedMaterials = Material::where('track_clicks', true)->pluck('id')->toArray();

        $machineId = $request->input('machine_id');
        $categoryId = $request->input('category_id');
        $productId = $request->input('product_id');
        $materialId = $request->input('material_id');
        $machineFeatureReady = $this->canUseMachineFeature();

        $baseQuery = OrderItem::query()
            ->select([
                'order_items.product_id',
                'order_items.product_name',
                'order_items.material_id',
                'order_items.material_name',
                DB::raw('COUNT(DISTINCT order_items.order_id) as total_orders'),
                DB::raw('SUM(order_items.qty) as total_qty'),
                DB::raw('SUM(order_items.qty * COALESCE(order_items.sisi, 1)) as total_clicks'),
                DB::raw('SUM(order_items.size_value) as total_size'),
                DB::raw('SUM(order_items.subtotal) as total_sales'),
            ])
            ->join('orders', 'order_items.order_id', '=', 'orders.id')
            ->leftJoin('materials', 'order_items.material_id', '=', 'materials.id')
            ->where(function ($query) use ($trackedProducts, $trackedMaterials) {
                $query->whereIn('order_items.product_id', $trackedProducts)
                    ->orWhereIn('order_items.material_id', $trackedMaterials);
            })
            ->when($machineId && $machineFeatureReady, function ($q) use ($machineId) {
                $q->whereHas('material.machines', function ($mq) use ($machineId) {
                    $mq->where('machines.id', $machineId);
                });
            })
            ->when($categoryId, function ($q) use ($categoryId) {
                $q->where('materials.category_id', $categoryId);
            })
            ->when($productId, function ($q) use ($productId) {
                $q->where('order_items.product_id', $productId);
            })
            ->when($materialId, function ($q) use ($materialId) {
                $q->where('order_items.material_id', $materialId);
            })
            ->whereBetween('orders.created_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59'])
            ->groupBy('order_items.product_id', 'order_items.product_name', 'order_items.material_id', 'order_items.material_name');

        $allReportData = (clone $baseQuery)->get();

        $dailyData = OrderItem::query()
            ->select([
                DB::raw('DATE(orders.created_at) as date'),
                DB::raw('SUM(order_items.qty * COALESCE(order_items.sisi, 1)) as total_clicks')
            ])
            ->join('orders', 'order_items.order_id', '=', 'orders.id')
            ->leftJoin('materials', 'order_items.material_id', '=', 'materials.id')
            ->where(function ($query) use ($trackedProducts, $trackedMaterials) {
                $query->whereIn('order_items.product_id', $trackedProducts)
                    ->orWhereIn('order_items.material_id', $trackedMaterials);
            })
            ->when($machineId && $machineFeatureReady, function ($q) use ($machineId) {
                $q->whereHas('material.machines', function ($mq) use ($machineId) {
                    $mq->where('machines.id', $machineId);
                });
            })
            ->when($categoryId, function ($q) use ($categoryId) {
                $q->where('materials.category_id', $categoryId);
            })
            ->when($productId, function ($q) use ($productId) {
                $q->where('order_items.product_id', $productId);
            })
            ->when($materialId, function ($q) use ($materialId) {
                $q->where('order_items.material_id', $materialId);
            })
            ->whereBetween('orders.created_at', [$startDate . ' 00:00:00', $endDate . ' 23:59:59'])
            ->groupBy('date')
            ->orderBy('date')
            ->get();

        $machines = $this->getMachinesForReport();
        $machineStats = [];
        $totalClickCost = 0;

        $materialMachines = [];
        $materialMachineCostPerClick = [];
        $reportMaterialIds = $allReportData->pluck('material_id')->unique()->filter()->values()->all();

        if ($machineFeatureReady && !empty($reportMaterialIds)) {
            $materialsWithMachines = Material::whereIn('id', $reportMaterialIds)
                ->with(['machines' => function ($query) {
                    $machineTable = (new Machine())->getTable();

                    if (Schema::hasColumn($machineTable, 'is_active')) {
                        $query->where('is_active', true);
                    }

                    $query->orderBy('name');
                }])
                ->get();

            foreach ($materialsWithMachines as $material) {
                $machineNames = $material->machines
                    ->pluck('name')
                    ->filter()
                    ->unique()
                    ->values()
                    ->all();

                $materialMachines[$material->id] = !empty($machineNames)
                    ? implode(', ', $machineNames)
                    : '-';

                $materialMachineCostPerClick[$material->id] = (float) $material->machines->sum(function ($machine) {
                    return (float) ($machine->cost_per_click ?? 0);
                });
            }
        }

        foreach ($machines as $machine) {
            $linkedMaterialIds = $machine->materials()
                ->whereIn('materials.id', $reportMaterialIds)
                ->pluck('materials.id')
                ->toArray();

            if (empty($linkedMaterialIds)) {
                $machineStats[] = [
                    'id' => $machine->id,
                    'name' => $machine->name,
                    'cost_per_click' => $machine->cost_per_click ?? 0,
                    'total_clicks' => 0,
                    'total_cost' => 0,
                ];
                continue;
            }

            $clicks = (float) $allReportData->whereIn('material_id', $linkedMaterialIds)->sum('total_clicks');
            $cost = $clicks * (float) ($machine->cost_per_click ?? 0);

            $machineStats[] = [
                'id' => $machine->id,
                'name' => $machine->name,
                'cost_per_click' => $machine->cost_per_click ?? 0,
                'total_clicks' => $clicks,
                'total_cost' => $cost,
            ];
        }

        foreach ($allReportData as $row) {
            $totalClickCost += ((float) ($row->total_clicks ?? 0)) * ((float) ($materialMachineCostPerClick[$row->material_id] ?? 0));
        }

        $summary = [
            'total_orders' => (float) $allReportData->sum('total_orders'),
            'total_qty' => (float) $allReportData->sum('total_qty'),
            'total_clicks' => (float) $allReportData->sum('total_clicks'),
            'total_cost' => (float) $totalClickCost,
            'total_size' => (float) $allReportData->sum('total_size'),
            'total_sales' => (float) $allReportData->sum('total_sales'),
        ];

        $reportData = $baseQuery->orderByDesc('total_sales')
            ->paginate($perPage)
            ->through(function ($row) use ($materialMachines, $materialMachineCostPerClick) {
                $costPerClick = (float) ($materialMachineCostPerClick[$row->material_id] ?? 0);
                $totalClicks = (float) ($row->total_clicks ?? 0);

                $row->machine_names = $materialMachines[$row->material_id] ?? '-';
                $row->cost_per_click = $costPerClick;
                $row->total_cost = $totalClicks * $costPerClick;

                return $row;
            })
            ->withQueryString();

        $byProduct = $allReportData->groupBy('product_name');
        $byMaterial = $allReportData->groupBy('material_name');

        $products = Product::where('track_clicks', true)->orderBy('name')->get();
        $materials = Material::where('track_clicks', true)->orderBy('name')->get();
        $categories = MaterialCategory::orderBy('name')->get();

        return view('pages.reports.clicks', [
            'title' => 'Laporan Klik',
            'reportData' => $reportData,
            'summary' => $summary,
            'byProduct' => $byProduct,
            'byMaterial' => $byMaterial,
            'dailyData' => $dailyData,
            'machineStats' => $machineStats,
            'materialMachines' => $materialMachines,
            'materialMachineCostPerClick' => $materialMachineCostPerClick,
            'products' => $products,
            'materials' => $materials,
            'machines' => $machines,
            'categories' => $categories,
            'startDate' => $startDate,
            'endDate' => $endDate,
        ]);
    }

    private function canUseMachineFeature(): bool
    {
        if (!class_exists(Machine::class)) {
            return false;
        }

        if (!Schema::hasTable((new Machine())->getTable())) {
            return false;
        }

        if (!method_exists(Material::class, 'machines')) {
            return false;
        }

        try {
            $pivotTable = (new Material())->machines()->getTable();

            if (empty($pivotTable) || !Schema::hasTable($pivotTable)) {
                return false;
            }
        } catch (\Throwable $e) {
            return false;
        }

        return true;
    }

    private function getMachinesForReport()
    {
        if (!$this->canUseMachineFeature()) {
            return collect();
        }

        $machineTable = (new Machine())->getTable();
        $query = Machine::query()->orderBy('name');

        if (Schema::hasColumn($machineTable, 'is_active')) {
            $query->where('is_active', true);
        }

        return $query->get();
    }
}
