<?php

namespace App\Services\Inventory;

use App\Models\InventoryCategory;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class InventoryCategoryService
{
    private array $types = ['classroom', 'book', 'office', 'kitchen'];

    public function list(?string $type = null): array
    {
        $query = InventoryCategory::query()->orderBy('name');
        if ($type) {
            $query->where('type', $this->normalizeType($type));
        }
        return $query->get()->toArray();
    }

    public function create(array $data): array
    {
        try {
            $payload = $this->normalizePayload($data);
        } catch (\InvalidArgumentException $e) {
            return ['ok' => false, 'message' => $e->getMessage()];
        }
        $existing = InventoryCategory::query()
            ->where('type', $payload['type'])
            ->where('name', $payload['name'])
            ->first();
        if ($existing) {
            return ['ok' => false, 'message' => 'This category already exists.'];
        }

        try {
            $category = InventoryCategory::query()->create($payload);
        } catch (\Throwable $e) {
            Log::error('Inventory category create failed: ' . $e->getMessage());
            return ['ok' => false, 'message' => 'Failed to save category.'];
        }

        return ['ok' => true, 'category' => $category->toArray()];
    }

    public function update(int $id, array $data): array
    {
        $category = InventoryCategory::query()->find($id);
        if (!$category) {
            return ['ok' => false, 'message' => 'Category not found.'];
        }

        try {
            $payload = $this->normalizePayload($data, (string) $category->type);
        } catch (\InvalidArgumentException $e) {
            return ['ok' => false, 'message' => $e->getMessage()];
        }
        $existing = InventoryCategory::query()
            ->where('type', $payload['type'])
            ->where('name', $payload['name'])
            ->where('id', '!=', $id)
            ->first();
        if ($existing) {
            return ['ok' => false, 'message' => 'A category with this Type & Name already exists.'];
        }

        try {
            $category->update($payload);
        } catch (\Throwable $e) {
            Log::error('Inventory category update failed: ' . $e->getMessage());
            return ['ok' => false, 'message' => 'Failed to save category.'];
        }

        return ['ok' => true, 'category' => $category->toArray()];
    }

    public function delete(int $id): array
    {
        $category = InventoryCategory::query()->find($id);
        if (!$category) {
            return ['ok' => false, 'message' => 'Category not found.'];
        }

        try {
            $category->delete();
        } catch (\Throwable $e) {
            Log::error('Inventory category delete failed: ' . $e->getMessage());
            return ['ok' => false, 'message' => 'Failed to delete category.'];
        }

        return ['ok' => true];
    }

    private function normalizePayload(array $data, ?string $lockedType = null): array
    {
        $type = $lockedType ?? $this->normalizeType($data['type'] ?? 'office');
        $name = preg_replace('/\\s+/', ' ', trim((string) ($data['name'] ?? '')));

        $payload = [
            'type' => $type,
            'name' => $name,
            'description' => (string) ($data['description'] ?? ''),
            'grade_min' => null,
            'grade_max' => null,
        ];

        if ($type === 'book') {
            $gmin = $data['grade_min'] ?? null;
            $gmax = $data['grade_max'] ?? null;
            $gmin = ($gmin === '' || $gmin === null) ? null : max(0, (int) $gmin);
            $gmax = ($gmax === '' || $gmax === null) ? null : max(0, (int) $gmax);
            if ($gmin !== null && $gmax !== null && $gmin > $gmax) {
                throw new \InvalidArgumentException('Grade Min cannot be greater than Grade Max.');
            }
            if ($gmin !== null && $gmin > 13) {
                $gmin = 13;
            }
            if ($gmax !== null && $gmax > 13) {
                $gmax = 13;
            }
            $payload['grade_min'] = $gmin;
            $payload['grade_max'] = $gmax;
        }

        return $payload;
    }

    private function normalizeType(?string $type): string
    {
        $type = strtolower((string) $type);
        return in_array($type, $this->types, true) ? $type : 'office';
    }
}
