<?php

namespace App\Http\Controllers\Admin;

use App\Actions\Terminals\CreateTerminal;
use App\Actions\Terminals\DeleteTerminal;
use App\Actions\Terminals\ExportTerminals;
use App\Actions\Terminals\UpdateTerminal;
use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\TerminalRequest;
use App\Models\Store;
use App\Models\Terminal;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;

/**
 * Master-detail CRUD for checkout terminals (Settings → Terminals).
 * Same shape as {@see BrandController}: flat list on the left, sticky
 * editor on the right; saves/deletes run over AJAX and the server
 * returns the freshly-rendered list HTML for a one-shot client swap.
 *
 * The editor also configures the terminal's hardware (receipt-printer
 * mode + WebUSB pairing, paper, cut, cash drawer), folded into the
 * `default_printer_config` JSON by {@see TerminalRequest}.
 */
class TerminalController extends Controller
{
    public function index(Request $request): View
    {
        $this->authorize('viewAny', Terminal::class);

        $terminals = $this->orderedTerminals();
        $stores    = Store::query()->active()->ordered()->get(['id', 'name']);

        $selectedId = $request->integer('selected');
        $isNew      = $request->boolean('new');

        $selected = $selectedId
            ? $terminals->firstWhere('id', $selectedId)
            : null;

        return view('admin.terminals.index', [
            'terminals'        => $terminals,
            'stores'           => $stores,
            'selected'         => $selected,
            'isNew'            => $isNew,
            // Which terminal THIS browser is currently bound to, if any.
            'activeTerminalId' => current_terminal_id(),
        ]);
    }

    /**
     * Bind the current browser/workstation to a terminal by setting the
     * long-lived `pos_terminal_id` cookie that {@see current_terminal()}
     * reads. Because a terminal is scoped to one store, this also makes
     * that store the active store so the binding resolves immediately
     * (mirrors {@see StoreSwitchController}, including its access guard).
     */
    public function select(Request $request, Terminal $terminal): JsonResponse
    {
        $this->authorize('viewAny', Terminal::class);

        if (! $terminal->is_active) {
            return response()->json([
                'ok'      => false,
                'message' => __('terminals.select.inactive'),
            ], 422);
        }

        $user = $request->user();
        abort_unless($user && $user->canAccessStore($terminal->store_id), 403);

        $from = current_store_id();
        if ($from !== $terminal->store_id) {
            $request->session()->put('active_store_id', $terminal->store_id);
            do_action('store.switched', $from, $terminal->store_id, $user);
        }

        cookie()->queue(cookie()->forever('pos_terminal_id', (string) $terminal->id));

        return response()->json([
            'ok'          => true,
            'message'     => __('terminals.select.flash', ['name' => $terminal->name]),
            'selected_id' => $terminal->id,
        ]);
    }

    /** Unbind this browser from any terminal (clears the cookie). */
    public function clearSelection(Request $request): JsonResponse
    {
        $this->authorize('viewAny', Terminal::class);

        cookie()->queue(cookie()->forget('pos_terminal_id'));

        return response()->json([
            'ok'          => true,
            'message'     => __('terminals.select.cleared'),
            'selected_id' => null,
        ]);
    }

    public function store(TerminalRequest $request, CreateTerminal $create): RedirectResponse|JsonResponse
    {
        $this->authorize('create', Terminal::class);

        $terminal = ($create)($request->persistedAttributes());
        $message  = __('terminals.flash.created', ['name' => $terminal->name]);

        if ($request->wantsJson()) {
            return $this->freshListJson($terminal->id, $message);
        }

        return redirect()
            ->route('admin.terminals.index', ['selected' => $terminal->id])
            ->with('success', $message);
    }

    public function update(TerminalRequest $request, Terminal $terminal, UpdateTerminal $update): RedirectResponse|JsonResponse
    {
        $this->authorize('update', $terminal);

        ($update)($terminal, $request->persistedAttributes());
        $message = __('terminals.flash.updated', ['name' => $terminal->name]);

        if ($request->wantsJson()) {
            return $this->freshListJson($terminal->id, $message);
        }

        return redirect()
            ->route('admin.terminals.index', ['selected' => $terminal->id])
            ->with('success', $message);
    }

    public function destroy(Request $request, Terminal $terminal, DeleteTerminal $delete): RedirectResponse|JsonResponse
    {
        $this->authorize('delete', $terminal);

        $name = $terminal->name;
        ($delete)($terminal);
        $message = __('terminals.flash.deleted', ['name' => $name]);

        if ($request->wantsJson()) {
            return $this->freshListJson(null, $message);
        }

        return redirect()
            ->route('admin.terminals.index')
            ->with('success', $message);
    }

    public function export(Request $request, ExportTerminals $export): \Symfony\Component\HttpFoundation\StreamedResponse
    {
        $this->authorize('viewAny', Terminal::class);

        $format = $request->query('format', 'csv');
        if (! in_array($format, ['csv', 'xlsx'], true)) {
            abort(422, 'Unsupported export format. Use csv or xlsx.');
        }

        return ($export)($format);
    }

    /* ── Helpers ────────────────────────────────────────────────── */

    /** @return \Illuminate\Database\Eloquent\Collection<int, Terminal> */
    private function orderedTerminals(): \Illuminate\Database\Eloquent\Collection
    {
        return Terminal::query()->with('store:id,name')->ordered()->get();
    }

    /** Build the JSON the client uses to refresh the list after a save/delete. */
    private function freshListJson(?int $selectedId, string $message): JsonResponse
    {
        $terminals = $this->orderedTerminals();

        $listHtml = view('admin.terminals._list', ['terminals' => $terminals])->render();

        $rows = $terminals->map(fn (Terminal $t) => [
            'id'         => $t->id,
            'store_id'   => $t->store_id,
            'store_name' => $t->store?->name,
            'code'       => $t->code,
            'name'       => $t->name,
            'is_active'  => (bool) $t->is_active,
            'config'     => $t->default_printer_config['receipt_printer'] ?? null,
            'updated_at' => $t->updated_at?->diffForHumans(),
        ])->values();

        return response()->json([
            'ok'        => true,
            'message'   => $message,
            'id'        => $selectedId,
            'list_html' => $listHtml,
            'rows'      => $rows,
        ]);
    }
}
