<?php

namespace Modules\VetClinic\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Modules\VetClinic\Entities\VcSoapOption;
use Modules\VetClinic\Entities\VcModuleSetting;

class VcSoapOptionController extends Controller
{
    private const SECTIONS = ['complaint', 'lab_test', 'exam_test', 'frequency', 'body_system'];
    private const SPECIES   = ['all', 'dog', 'cat', 'rabbit', 'bird'];

    public function index()
    {
        if (!auth()->user()->can('vet_clinic.access_settings')) {
            abort(403);
        }

        $businessId = request()->session()->get('user.business_id');

        $all = VcSoapOption::where(function ($q) use ($businessId) {
                $q->whereNull('business_id')->orWhere('business_id', $businessId);
            })
            ->orderBy('section')
            ->orderBy('sort_order')
            ->orderBy('label')
            ->get();

        // Hide system defaults that have been overridden by a business copy
        // (matching by section + species + label) so the settings page doesn't
        // show duplicates.
        $businessKeys = $all->where('business_id', $businessId)
            ->map(fn($o) => $this->optionKey($o))->all();
        $options = $all
            ->reject(function ($o) use ($businessId, $businessKeys) {
                return is_null($o->business_id) && in_array($this->optionKey($o), $businessKeys, true);
            })
            ->values()
            ->groupBy('section');

        $savedGroupIcons = json_decode(VcModuleSetting::get($businessId, 'soap_group_icons', '{}'), true) ?: [];

        return view('vetClinic::settings.soap-options', compact('options', 'savedGroupIcons'));
    }

    /** AJAX: return active options for a given section + species (used by show.blade) */
    public function data(Request $request)
    {
        $businessId = request()->session()->get('user.business_id');
        $section    = $request->section;
        $species    = $request->species ?? 'all';

        if (!in_array($section, self::SECTIONS)) {
            return response()->json([]);
        }

        $all = VcSoapOption::forBusiness($businessId, $section, $species);
        $shadowed = $this->shadowedSystemKeys($businessId, $section);

        $rows = $all
            ->reject(function ($o) use ($shadowed) {
                // Hide system defaults that the business has overridden with its own copy
                return is_null($o->business_id) && in_array($this->optionKey($o), $shadowed, true);
            })
            ->values()
            ->map(fn($o) => [
                'id'         => $o->id,
                'label'      => $o->label,
                'species'    => $o->species,
                'group_name' => $o->group_name,
                'product_id' => $o->product_id ?? null,
                'price'      => $this->priceFor($o->product_id ?? null),
            ]);

        if ($section === 'body_system') {
            $groupIcons = json_decode(VcModuleSetting::get($businessId, 'soap_group_icons', '{}'), true) ?: [];
            $rows = $rows->map(function ($item) use ($groupIcons) {
                $meta = $groupIcons[$item['group_name']] ?? [];
                $item['group_icon']  = $meta['icon']  ?? null;
                $item['group_color'] = $meta['color'] ?? null;
                $item['group_bg']    = $meta['bg']    ?? null;
                return $item;
            });
        }

        return response()->json($rows);
    }

    /** AJAX: search all matching options — JS handles deduplication with visible chips */
    public function search(Request $request)
    {
        $businessId = request()->session()->get('user.business_id');
        $section    = $request->section;
        $species    = $request->species ?? 'all';
        $term       = trim($request->q ?? '');

        if (!in_array($section, self::SECTIONS) || strlen($term) < 1) {
            return response()->json([]);
        }

        $shadowed = $this->shadowedSystemKeys($businessId, $section);

        $rows = VcSoapOption::active()
            ->section($section)
            ->where(function ($q) use ($businessId) {
                $q->whereNull('business_id')->orWhere('business_id', $businessId);
            })
            ->where(function ($q) use ($species) {
                $q->where('species', 'all')->orWhere('species', $species);
            })
            ->where('label', 'like', '%' . $term . '%')
            ->orderBy('sort_order')
            ->orderBy('label')
            ->limit(40)
            ->get()
            ->reject(function ($o) use ($shadowed) {
                return is_null($o->business_id) && in_array($this->optionKey($o), $shadowed, true);
            })
            ->take(20)
            ->values()
            ->map(fn($o) => ['id' => $o->id, 'label' => $o->label]);

        return response()->json($rows);
    }

    public function store(Request $request)
    {
        if (!auth()->user()->can('vet_clinic.access_settings')) {
            abort(403);
        }

        $request->validate([
            'section'    => 'required|in:' . implode(',', self::SECTIONS),
            'species'    => 'required|in:' . implode(',', self::SPECIES),
            'label'      => 'required|string|max:120',
            'sort_order' => 'nullable|integer|min:0',
            'group_name' => 'nullable|string|max:60',
            'group_icon' => 'nullable|string|max:40',
        ]);

        $businessId = request()->session()->get('user.business_id');

        $exists = VcSoapOption::where('business_id', $businessId)
            ->where('section', $request->section)
            ->where('species', $request->species)
            ->where('label', $request->label)
            ->exists();

        if ($exists) {
            return response()->json(['success' => false, 'msg' => 'Option already exists.'], 422);
        }

        $option = VcSoapOption::create([
            'business_id' => $businessId,
            'section'     => $request->section,
            'species'     => $request->species,
            'label'       => $request->label,
            'sort_order'  => $request->sort_order ?? 0,
            'group_name'  => $request->section === 'body_system' ? ($request->group_name ?: null) : null,
            'product_id'  => in_array($request->section, ['lab_test', 'exam_test']) && $request->filled('product_id') ? (int) $request->product_id : null,
            'status'      => 'active',
        ]);

        // Persist group icon if provided (stored as JSON in module settings)
        if ($request->section === 'body_system' && $request->group_name && $request->group_icon) {
            $groupIcons = json_decode(VcModuleSetting::get($businessId, 'soap_group_icons', '{}'), true) ?: [];
            if (empty($groupIcons[$request->group_name])) {
                $groupIcons[$request->group_name] = ['icon' => $request->group_icon];
                VcModuleSetting::set($businessId, 'soap_group_icons', json_encode($groupIcons));
            }
        }

        return response()->json(['success' => true, 'msg' => 'Option added.', 'option' => ['id' => $option->id, 'label' => $option->label, 'group_name' => $option->group_name]]);
    }

    public function update(Request $request, $id)
    {
        if (!auth()->user()->can('vet_clinic.access_settings')) {
            abort(403);
        }

        $request->validate([
            'label'      => 'required|string|max:120',
            'sort_order' => 'nullable|integer|min:0',
            'status'     => 'required|in:active,inactive',
            'group_name' => 'nullable|string|max:60',
        ]);

        $businessId = request()->session()->get('user.business_id');
        $option = $this->resolveOrPromote($id, $businessId);
        $wasPromoted = $option->wasRecentlyCreated;

        $option->update([
            'label'      => $request->label,
            'sort_order' => $request->sort_order ?? $option->sort_order,
            'status'     => $request->status,
            'group_name' => $option->section === 'body_system' ? ($request->group_name ?: null) : $option->group_name,
            'product_id' => in_array($option->section, ['lab_test', 'exam_test'])
                ? ($request->filled('product_id') ? (int) $request->product_id : null)
                : $option->product_id,
        ]);

        return response()->json([
            'success'  => true,
            'msg'      => $wasPromoted ? 'Option overridden for this business.' : 'Option updated.',
            'id'       => $option->id,
            'promoted' => $wasPromoted,
        ]);
    }

    /** Resolve a product's default sell price (via primary variation). */
    private function priceFor($productId): ?float
    {
        if (!$productId) return null;
        $row = \DB::table('variations')
            ->where('product_id', $productId)
            ->whereNull('deleted_at')
            ->orderBy('id')
            ->first(['default_sell_price']);
        return $row ? (float) $row->default_sell_price : null;
    }

    /** Update a body-system group's name and/or icon */
    public function updateGroup(Request $request)
    {
        if (!auth()->user()->can('vet_clinic.access_settings')) {
            abort(403);
        }

        $request->validate([
            'old_name'   => 'required|string|max:60',
            'new_name'   => 'required|string|max:60',
            'group_icon' => 'nullable|string|max:40',
        ]);

        $businessId = request()->session()->get('user.business_id');
        $oldName    = $request->old_name;
        $newName    = $request->new_name;

        // Rename group_name on all rows this business owns
        if ($oldName !== $newName) {
            VcSoapOption::where('business_id', $businessId)
                ->where('section', 'body_system')
                ->where('group_name', $oldName)
                ->update(['group_name' => $newName]);
        }

        // Update group icon/name in per-business VcModuleSetting JSON
        $groupIcons = json_decode(VcModuleSetting::get($businessId, 'soap_group_icons', '{}'), true) ?: [];

        if ($oldName !== $newName && isset($groupIcons[$oldName])) {
            $groupIcons[$newName] = $groupIcons[$oldName];
            unset($groupIcons[$oldName]);
        }

        if ($request->group_icon) {
            if (!isset($groupIcons[$newName])) {
                $groupIcons[$newName] = [];
            }
            $groupIcons[$newName]['icon'] = $request->group_icon;
        }

        VcModuleSetting::set($businessId, 'soap_group_icons', json_encode($groupIcons));

        return response()->json(['success' => true, 'msg' => 'Group updated.']);
    }

    public function destroy($id)
    {
        if (!auth()->user()->can('vet_clinic.access_settings')) {
            abort(403);
        }

        $businessId = request()->session()->get('user.business_id');
        $option = VcSoapOption::where('business_id', $businessId)->findOrFail($id);
        $option->delete();

        return response()->json(['success' => true, 'msg' => 'Option deleted.']);
    }

    public function toggleStatus($id)
    {
        if (!auth()->user()->can('vet_clinic.access_settings')) {
            abort(403);
        }

        $businessId = request()->session()->get('user.business_id');
        $option     = $this->resolveOrPromote($id, $businessId);
        $option->update(['status' => $option->status === 'active' ? 'inactive' : 'active']);

        return response()->json([
            'success'  => true,
            'status'   => $option->status,
            'id'       => $option->id,
            'promoted' => $option->wasRecentlyCreated,
        ]);
    }

    /**
     * Return a business-owned VcSoapOption for $id. If $id points at a system default
     * (business_id IS NULL), clone it into a business-owned override and return that.
     * Subsequent calls find the existing override (no duplicate created).
     */
    private function resolveOrPromote(int $id, int $businessId): VcSoapOption
    {
        $option = VcSoapOption::findOrFail($id);

        // Already owned by this business → use it directly
        if ($option->business_id == $businessId) {
            return $option;
        }

        // Belongs to a different business → reject
        if (!is_null($option->business_id)) {
            abort(404);
        }

        // It's a system default — find or create a business-scoped override
        $existing = VcSoapOption::where('business_id', $businessId)
            ->where('section', $option->section)
            ->where('species', $option->species)
            ->where('label',   $option->label)
            ->first();

        if ($existing) {
            return $existing;
        }

        return VcSoapOption::create([
            'business_id' => $businessId,
            'section'     => $option->section,
            'species'     => $option->species,
            'label'       => $option->label,
            'sort_order'  => $option->sort_order ?? 0,
            'group_name'  => $option->group_name,
            'product_id'  => $option->product_id ?? null,
            'status'      => $option->status,
        ]);
    }

    /**
     * Stable lookup key for "same option" matching across system + business rows.
     * Two rows compare equal when section + species + label all match.
     */
    private function optionKey($o): string
    {
        return ($o->section ?? '') . '|' . ($o->species ?? '') . '|' . strtolower(trim($o->label ?? ''));
    }

    /**
     * Lookup keys for every business-owned option in a section. Used to hide
     * the corresponding system defaults from data/search/list output.
     */
    private function shadowedSystemKeys(int $businessId, string $section): array
    {
        return VcSoapOption::where('business_id', $businessId)
            ->where('section', $section)
            ->get(['section', 'species', 'label'])
            ->map(fn($o) => $this->optionKey($o))
            ->all();
    }
}
