<?php

namespace App\Http\Controllers\Admin;

use App\Models\TaxRate;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;

class TaxController extends AdminController
{
    public function index()
    {
        $taxes = TaxRate::with('members')
            ->where('company_id', $this->companyId())
            ->orderBy('is_group')
            ->orderBy('name')
            ->get();

        return view('admin.preferences.taxes.index', [
            'taxes' => $taxes,
            'activeSection' => 'taxes',
        ]);
    }

    public function createTax()
    {
        return view('admin.preferences.taxes.create-tax', [
            'tax' => null,
            'activeSection' => 'taxes',
        ]);
    }

    public function storeTax(Request $request)
    {
        $data = $this->validateTax($request);
        TaxRate::create(array_merge($data, [
            'company_id' => $this->companyId(),
            'is_group' => false,
            'is_active' => true,
        ]));

        return redirect()->route('admin.preferences.taxes')
            ->with('success', 'Tax created successfully.');
    }

    public function editTax(TaxRate $tax)
    {
        $this->authorizeTax($tax);

        if ($tax->is_group) {
            return redirect()->route('admin.preferences.taxes.groups.edit', $tax);
        }

        return view('admin.preferences.taxes.edit-tax', [
            'tax' => $tax,
            'activeSection' => 'taxes',
        ]);
    }

    public function updateTax(Request $request, TaxRate $tax)
    {
        $this->authorizeTax($tax);

        if ($tax->is_group) {
            abort(404);
        }

        $tax->update($this->validateTax($request));

        return redirect()->route('admin.preferences.taxes')
            ->with('success', 'Tax updated successfully.');
    }

    public function createGroup()
    {
        return view('admin.preferences.taxes.create-group', [
            'group' => null,
            'individualTaxes' => $this->individualTaxes(),
            'memberIds' => old('member_ids', ['', '', '']),
            'activeSection' => 'taxes',
        ]);
    }

    public function storeGroup(Request $request)
    {
        $data = $this->validateGroup($request);
        $memberIds = $this->parseMemberIds($request);

        DB::transaction(function () use ($data, $memberIds) {
            $group = TaxRate::create([
                'company_id' => $this->companyId(),
                'name' => $data['name'],
                'rate' => 0,
                'type' => 'other',
                'is_group' => true,
                'is_selectable' => $data['is_selectable'],
                'is_active' => true,
            ]);

            $this->syncGroupMembers($group, $memberIds);
            TaxRate::syncGroupRate($group);
        });

        return redirect()->route('admin.preferences.taxes')
            ->with('success', 'Tax group created successfully.');
    }

    public function editGroup(TaxRate $tax)
    {
        $this->authorizeTax($tax);

        if (! $tax->is_group) {
            return redirect()->route('admin.preferences.taxes.edit', $tax);
        }

        $tax->load('members');

        return view('admin.preferences.taxes.edit-group', [
            'group' => $tax,
            'individualTaxes' => $this->individualTaxes(),
            'memberIds' => old('member_ids', $tax->members->pluck('id')->all() ?: ['']),
            'activeSection' => 'taxes',
        ]);
    }

    public function updateGroup(Request $request, TaxRate $tax)
    {
        $this->authorizeTax($tax);

        if (! $tax->is_group) {
            abort(404);
        }

        $data = $this->validateGroup($request);
        $memberIds = $this->parseMemberIds($request);

        DB::transaction(function () use ($tax, $data, $memberIds) {
            $tax->update([
                'name' => $data['name'],
                'is_selectable' => $data['is_selectable'],
            ]);

            $this->syncGroupMembers($tax, $memberIds);
            TaxRate::syncGroupRate($tax);
        });

        return redirect()->route('admin.preferences.taxes')
            ->with('success', 'Tax group updated successfully.');
    }

    public function destroy(TaxRate $tax)
    {
        $this->authorizeTax($tax);
        $tax->delete();

        return redirect()->route('admin.preferences.taxes')
            ->with('success', 'Tax deleted successfully.');
    }

    private function individualTaxes()
    {
        return TaxRate::where('company_id', $this->companyId())
            ->individuals()
            ->active()
            ->orderBy('name')
            ->get();
    }

    private function validateTax(Request $request): array
    {
        $hasSurcharge = $request->boolean('has_surcharge');

        $validated = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'rate' => ['required', 'numeric', 'min:0', 'max:100'],
            'has_surcharge' => ['nullable', 'boolean'],
            'surcharge_rate' => [$hasSurcharge ? 'required' : 'nullable', 'numeric', 'min:0', 'max:100'],
            'is_selectable' => ['nullable', 'boolean'],
        ]);

        return [
            'name' => $validated['name'],
            'rate' => $validated['rate'],
            'type' => 'other',
            'has_surcharge' => $hasSurcharge,
            'surcharge_rate' => $hasSurcharge ? ($validated['surcharge_rate'] ?? null) : null,
            'is_selectable' => $request->boolean('is_selectable'),
        ];
    }

    private function validateGroup(Request $request): array
    {
        return $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'is_selectable' => ['nullable', 'boolean'],
            'member_ids' => ['required', 'array', 'min:1'],
            'member_ids.*' => [
                'nullable',
                'integer',
                Rule::exists('tax_rates', 'id')->where(function ($query) {
                    $query->where('company_id', $this->companyId())
                        ->where('is_group', false)
                        ->where('is_active', true);
                }),
            ],
        ], [
            'member_ids.required' => 'Select at least one tax for this group.',
            'member_ids.min' => 'Select at least one tax for this group.',
        ]);
    }

    /**
     * @return array<int, int>
     */
    private function parseMemberIds(Request $request): array
    {
        return collect($request->input('member_ids', []))
            ->filter(fn ($id) => filled($id))
            ->map(fn ($id) => (int) $id)
            ->unique()
            ->values()
            ->all();
    }

    private function syncGroupMembers(TaxRate $group, array $memberIds): void
    {
        if ($memberIds === []) {
            throw \Illuminate\Validation\ValidationException::withMessages([
                'member_ids' => 'Select at least one tax for this group.',
            ]);
        }

        $group->groupMembers()->delete();

        foreach ($memberIds as $index => $taxRateId) {
            $group->groupMembers()->create([
                'tax_rate_id' => $taxRateId,
                'sort_order' => $index,
            ]);
        }
    }

    private function authorizeTax(TaxRate $tax): void
    {
        if ($tax->company_id !== $this->companyId()) {
            abort(403);
        }
    }
}
