<?php

namespace App\Services\Inventory;

use App\Models\InventoryItem;
use Illuminate\Support\Facades\DB;

class InventorySummaryService
{
    public function __construct(private InventoryContextService $context)
    {
    }

    public function summary(string $type, ?string $schoolYear): array
    {
        $type = strtolower($type);
        $selectedYear = trim((string) ($schoolYear ?? $this->context->schoolYear()));

        $items = InventoryItem::query()
            ->where('type', $type)
            ->orderBy('name')
            ->get()
            ->toArray();

        $itemIds = array_map(static fn ($i) => (int) ($i['id'] ?? 0), $items);
        $agg = [];
        if (!empty($itemIds)) {
            $qb = DB::table('inventory_movements')
                ->selectRaw('item_id,
                    SUM(CASE WHEN qty_change>0 THEN qty_change ELSE 0 END) AS received,
                    SUM(CASE WHEN qty_change<0 THEN -qty_change ELSE 0 END) AS issued')
                ->whereIn('item_id', $itemIds)
                ->groupBy('item_id');

            if (strtolower($selectedYear) !== 'all' && $selectedYear !== '') {
                $qb->where('school_year', $selectedYear);
            }

            foreach ($qb->get() as $row) {
                $agg[(int) $row->item_id] = [
                    'received' => (int) ($row->received ?? 0),
                    'issued' => (int) ($row->issued ?? 0),
                ];
            }
        }

        return [
            'items' => $items,
            'agg' => $agg,
            'selectedYear' => $selectedYear,
            'currentYear' => $this->context->schoolYear(),
            'schoolYears' => $this->getSchoolYearsForType($type),
        ];
    }

    public function summaryAll(?string $schoolYear, ?string $type): array
    {
        $selectedYear = trim((string) ($schoolYear ?? $this->context->schoolYear()));
        $selectedType = strtolower((string) ($type ?? 'all'));
        $isAllYears = strtolower($selectedYear) === 'all';

        $qbItems = DB::table('inventory_items as i')
            ->select('i.*', 'c.name AS category_name', DB::raw("CONCAT(u.firstname, ' ', u.lastname) AS updated_by_name"))
            ->leftJoin('inventory_categories as c', 'c.id', '=', 'i.category_id')
            ->leftJoin('users as u', 'u.id', '=', 'i.updated_by')
            ->orderBy('i.name');

        if (!$isAllYears) {
            $qbItems->where('i.school_year', $selectedYear);
        }

        if (in_array($selectedType, ['book', 'classroom', 'office', 'kitchen'], true)) {
            $qbItems->where('i.type', $selectedType);
        }

        $items = $qbItems->get()->map(fn ($r) => (array) $r)->all();

        $rows = [];
        $totals = [
            'opening' => 0,
            'received' => 0,
            'distributed' => 0,
            'other_out' => 0,
            'adjust_net' => 0,
            'ending' => 0,
            'onhand' => 0,
            'variance' => 0,
        ];

        if (!empty($items)) {
            $itemIds = array_map('intval', array_column($items, 'id'));
            $aggById = [];
            $qb = DB::table('inventory_movements as m')
                ->selectRaw("
                    m.item_id,
                    SUM(CASE WHEN m.movement_type = 'initial' THEN m.qty_change ELSE 0 END) AS opening,
                    SUM(CASE WHEN m.qty_change > 0 AND m.movement_type IN ('in','adjust') THEN m.qty_change ELSE 0 END) AS received,
                    SUM(CASE WHEN m.qty_change < 0 AND m.movement_type = 'distribution' THEN -m.qty_change ELSE 0 END) AS distributed,
                    SUM(CASE WHEN m.qty_change < 0 AND m.movement_type = 'out' THEN -m.qty_change ELSE 0 END) AS other_out,
                    SUM(CASE WHEN m.movement_type = 'adjust' THEN m.qty_change ELSE 0 END) AS adjust_net
                ")
                ->whereIn('m.item_id', $itemIds)
                ->groupBy('m.item_id');

            if (!$isAllYears) {
                $qb->where('m.school_year', $selectedYear);
            }

            foreach ($qb->get()->map(fn ($r) => (array) $r)->all() as $r) {
                $aggById[(int) $r['item_id']] = [
                    'opening' => (int) ($r['opening'] ?? 0),
                    'received' => (int) ($r['received'] ?? 0),
                    'distributed' => (int) ($r['distributed'] ?? 0),
                    'other_out' => (int) ($r['other_out'] ?? 0),
                    'adjust_net' => (int) ($r['adjust_net'] ?? 0),
                ];
            }

            foreach ($items as $it) {
                $id = (int) $it['id'];
                $a = $aggById[$id] ?? ['opening' => 0, 'received' => 0, 'distributed' => 0, 'other_out' => 0, 'adjust_net' => 0];

                $opening = (int) $a['opening'];
                $received = (int) $a['received'];
                $distributed = (int) $a['distributed'];
                $otherOut = (int) $a['other_out'];
                $adjustNet = (int) $a['adjust_net'];

                $ending = $opening + $received - $distributed - $otherOut + $adjustNet;
                $onhand = (int) ($it['quantity'] ?? 0);
                $variance = $onhand - $ending;

                $rows[] = [
                    'id' => $id,
                    'name' => (string) ($it['name'] ?? ''),
                    'type' => (string) ($it['type'] ?? ''),
                    'category' => (string) ($it['category_name'] ?? ''),
                    'opening' => $opening,
                    'received' => $received,
                    'distributed' => $distributed,
                    'other_out' => $otherOut,
                    'adjust_net' => $adjustNet,
                    'ending' => $ending,
                    'onhand' => $onhand,
                    'variance' => $variance,
                ];

                $totals['opening'] += $opening;
                $totals['received'] += $received;
                $totals['distributed'] += $distributed;
                $totals['other_out'] += $otherOut;
                $totals['adjust_net'] += $adjustNet;
                $totals['ending'] += $ending;
                $totals['onhand'] += $onhand;
                $totals['variance'] += $variance;
            }
        }

        return [
            'selectedYear' => $selectedYear,
            'currentYear' => $this->context->schoolYear(),
            'schoolYears' => $this->getSchoolYearsForType('book') ?: [$this->context->schoolYear(), 'All'],
            'rows' => $rows,
            'totals' => $totals,
            'selectedType' => $selectedType,
        ];
    }

    private function getSchoolYearsForType(string $type): array
    {
        $years = InventoryItem::query()
            ->select('school_year')
            ->where('type', $type)
            ->whereNotNull('school_year')
            ->groupBy('school_year')
            ->orderByDesc('school_year')
            ->pluck('school_year')
            ->map(fn ($v) => trim((string) $v))
            ->filter()
            ->unique()
            ->values()
            ->all();

        $currentYear = $this->context->schoolYear();
        if ($currentYear && !in_array($currentYear, $years, true)) {
            array_unshift($years, $currentYear);
        }

        return $years;
    }
}
