<?php

declare(strict_types=1);

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Http\Requests\StoreConfigGroupRequest;
use App\Models\Plan;
use App\Models\PlanConfigGroup;
use App\Models\PlanConfigOption;
use App\Models\PlanConfigValue;
use App\Models\SubscriptionConfigSelection;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;

class ConfigGroupController extends Controller
{
    public function index(Request $request): Response
    {
        $query = PlanConfigGroup::query()
            ->withCount(['options', 'plans']);

        if ($request->filled('mode') && $request->input('mode') !== 'all') {
            $query->where('mode', $request->input('mode'));
        }

        if ($request->filled('search')) {
            $query->where('name', 'like', '%'.$request->input('search').'%');
        }

        $configGroups = $query
            ->orderBy('sort_order')
            ->orderBy('name')
            ->get();

        return Inertia::render('Admin/ConfigGroups/Index', [
            'configGroups' => $configGroups,
            'filters' => [
                'mode' => $request->input('mode', 'all'),
                'search' => $request->input('search', ''),
            ],
        ]);
    }

    public function create(): Response
    {
        $plans = Plan::query()
            ->whereIn('status', ['active', 'internal'])
            ->orderBy('name')
            ->get(['id', 'name', 'service_type', 'status']);

        return Inertia::render('Admin/ConfigGroups/Create', [
            'plans' => $plans,
        ]);
    }

    public function store(StoreConfigGroupRequest $request): RedirectResponse
    {
        DB::transaction(function () use ($request): void {
            $group = PlanConfigGroup::query()->create([
                'name' => $request->validated('name'),
                'description' => $request->validated('description'),
                'mode' => $request->validated('mode'),
                'service_type' => $request->validated('service_type'),
                'is_active' => $request->boolean('is_active', true),
                'sort_order' => $request->validated('sort_order') ?? 0,
            ]);

            if ($request->validated('mode') === 'preset' && $request->has('plan_ids')) {
                $group->plans()->sync($request->validated('plan_ids'));
            }

            $this->syncOptions($group, $request->validated('options'));
        });

        return redirect()
            ->route('admin.config-groups.index')
            ->with('success', 'Config group created successfully.');
    }

    public function edit(PlanConfigGroup $configGroup): Response
    {
        $configGroup->load(['options.values', 'plans:id,name,service_type,status']);

        $plans = Plan::query()
            ->whereIn('status', ['active', 'internal'])
            ->orderBy('name')
            ->get(['id', 'name', 'service_type', 'status']);

        return Inertia::render('Admin/ConfigGroups/Edit', [
            'configGroup' => $configGroup,
            'plans' => $plans,
        ]);
    }

    public function update(StoreConfigGroupRequest $request, PlanConfigGroup $configGroup): RedirectResponse
    {
        DB::transaction(function () use ($request, $configGroup): void {
            $configGroup->update([
                'name' => $request->validated('name'),
                'description' => $request->validated('description'),
                'mode' => $request->validated('mode'),
                'service_type' => $request->validated('service_type'),
                'is_active' => $request->boolean('is_active', true),
                'sort_order' => $request->validated('sort_order') ?? 0,
            ]);

            if ($request->validated('mode') === 'preset') {
                $configGroup->plans()->sync($request->validated('plan_ids') ?? []);
            } else {
                $configGroup->plans()->detach();
            }

            $this->syncOptions($configGroup, $request->validated('options'));
        });

        return redirect()
            ->route('admin.config-groups.index')
            ->with('success', 'Config group updated successfully.');
    }

    public function destroy(PlanConfigGroup $configGroup): RedirectResponse
    {
        $hasSelections = SubscriptionConfigSelection::query()
            ->whereIn('option_id', $configGroup->options()->pluck('id'))
            ->exists();

        if ($hasSelections) {
            $configGroup->update(['is_active' => false]);
            $configGroup->delete();

            return redirect()
                ->route('admin.config-groups.index')
                ->with('success', 'Config group archived (has existing selections).');
        }

        $configGroup->options()->each(function (PlanConfigOption $option): void {
            $option->values()->delete();
        });
        $configGroup->options()->delete();
        $configGroup->plans()->detach();
        $configGroup->forceDelete();

        return redirect()
            ->route('admin.config-groups.index')
            ->with('success', 'Config group deleted permanently.');
    }

    /** @param array<int, array<string, mixed>> $optionsData */
    private function syncOptions(PlanConfigGroup $group, array $optionsData): void
    {
        $existingOptionIds = $group->options()->pluck('id')->toArray();
        $incomingOptionIds = [];

        foreach ($optionsData as $sortOrder => $optionData) {
            $optionId = $optionData['id'] ?? null;

            $optionAttributes = [
                'group_id' => $group->id,
                'name' => $optionData['name'],
                'description' => $optionData['description'] ?? null,
                'type' => $optionData['type'],
                'provisioning_key' => $optionData['provisioning_key'] ?? null,
                'required' => $optionData['required'] ?? false,
                'is_active' => $optionData['is_active'] ?? true,
                'min_qty' => $optionData['min_qty'] ?? null,
                'max_qty' => $optionData['max_qty'] ?? null,
                'step' => $optionData['step'] ?? null,
                'unit_label' => $optionData['unit_label'] ?? null,
                'hourly_price' => $optionData['hourly_price'] ?? null,
                'monthly_price' => $optionData['monthly_price'] ?? null,
                'quarterly_price' => $optionData['quarterly_price'] ?? null,
                'semi_annual_price' => $optionData['semi_annual_price'] ?? null,
                'annual_price' => $optionData['annual_price'] ?? null,
                'sort_order' => $sortOrder,
            ];

            if ($optionId && in_array($optionId, $existingOptionIds)) {
                $option = PlanConfigOption::query()->findOrFail($optionId);
                $option->update($optionAttributes);
                $incomingOptionIds[] = $optionId;
            } else {
                $option = PlanConfigOption::query()->create($optionAttributes);
            }

            $this->syncValues($option, $optionData['values'] ?? []);
        }

        $removedOptionIds = array_diff($existingOptionIds, $incomingOptionIds);
        if (! empty($removedOptionIds)) {
            PlanConfigValue::query()->whereIn('option_id', $removedOptionIds)->delete();
            PlanConfigOption::query()->whereIn('id', $removedOptionIds)->delete();
        }
    }

    /** @param array<int, array<string, mixed>> $valuesData */
    private function syncValues(PlanConfigOption $option, array $valuesData): void
    {
        $existingValueIds = $option->values()->pluck('id')->toArray();
        $incomingValueIds = [];

        foreach ($valuesData as $sortOrder => $valueData) {
            $valueId = $valueData['id'] ?? null;

            $valueAttributes = [
                'option_id' => $option->id,
                'label' => $valueData['label'],
                'value' => $valueData['value'] ?? null,
                'hourly_price' => $valueData['hourly_price'] ?? 0,
                'monthly_price' => $valueData['monthly_price'] ?? 0,
                'quarterly_price' => $valueData['quarterly_price'] ?? 0,
                'semi_annual_price' => $valueData['semi_annual_price'] ?? 0,
                'annual_price' => $valueData['annual_price'] ?? 0,
                'is_default' => $valueData['is_default'] ?? false,
                'sort_order' => $sortOrder,
            ];

            if ($valueId && in_array($valueId, $existingValueIds)) {
                $value = PlanConfigValue::query()->findOrFail($valueId);
                $value->update($valueAttributes);
                $incomingValueIds[] = $valueId;
            } else {
                PlanConfigValue::query()->create($valueAttributes);
            }
        }

        $removedValueIds = array_diff($existingValueIds, $incomingValueIds);
        if (! empty($removedValueIds)) {
            PlanConfigValue::query()->whereIn('id', $removedValueIds)->delete();
        }
    }
}
