<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Attivita;
use App\Models\Dispositivo;
use App\Models\Cucina;
use App\DataTables\DispositivoDataTable;
use App\DataTables\DispositivoDataTableEditor;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Illuminate\Routing\Controllers\Middleware;

class MappaDispositiviController extends Controller
{
    public static $permission_group = "Mappa Dispositivi";
    public static $permissions = [
        'view-mappa_dispositivi' => 'Vedi',
        'create-mappa_dispositivi' => 'Crea',
        'edit-mappa_dispositivi' => 'Modifica',
        'delete-mappa_dispositivi' => 'Elimina',
    ];
    
    public static function middleware(): array
    {
        return [
            new Middleware('permission:view-mappa_dispositivi', only: ['index']),
            new Middleware('permission:create-mappa_dispositivi|edit-mappa_dispositivi|delete-mappa_dispositivi', only: ['store', 'update', 'destroy']),
        ];
    }
    
    public function index(DispositivoDataTable $dataTable)
    {
        if (request()->ajax()) {
            return $dataTable->ajax();
        }

        return view('mappa_dispositivi.index', [
            'dispositiviByTipo' => self::buildDispositiviByTipo(),
            'tipiDispositivo' => Dispositivo::getTipoDispositivo(),
            'attivitaList' => Attivita::query()
                ->where('is_attiva', true)
                ->orderBy('nome')
                ->where('user_id', Auth::user()->id)
                ->get(['id', 'nome']),
        ]);
    }

    public function store(DispositivoDataTableEditor $editor)
    {
        $request = request();
        $input = $request->all();
        if($request->has('action')){
            switch($input['action']){
                case 'create':
                    if(!Auth::user()->can('create-mappa_dispositivi')) return;
                    break;
                case 'edit':
                    if(!Auth::user()->can('edit-mappa_dispositivi')) return;
                    break;
                case 'remove':
                    if(!Auth::user()->can('delete-mappa_dispositivi')) return;
                    break;
            }
        }
        return $editor->process($request);
    }
    public function show($dispositivo_id)
    {
        $dispositivo = Dispositivo::find($dispositivo_id);
        return view('mappa_dispositivi.show', ['dispositivo' => $dispositivo]);
    }

    /**
     * Elenco dispositivi raggruppati per tipologia (tab mappa).
     */
    public static function buildDispositiviByTipo(): array
    {
        $tipi = Dispositivo::getTipoDispositivo()->keys()->all();
        $grouped = array_fill_keys($tipi, []);
        $grouped['_altro'] = [];

        $attivitaAttiveIds = Attivita::query()
            ->where('is_attiva', true)
            ->pluck('id');

        $devices = Dispositivo::query()
            ->with('attivita:id,nome')
            ->where(function ($q) use ($attivitaAttiveIds) {
                $q->whereIn('attivita_id', $attivitaAttiveIds)
                    ->orWhereNull('attivita_id');
            })
            ->orderBy('nome')
            ->get(['id', 'nome', 'ubicazione', 'tipo', 'is_attivo', 'occupato', 'attivita_id']);

        foreach ($devices as $device) {
            $tipo = $device->tipo ?? '_altro';
            $bucket = isset($grouped[$tipo]) ? $tipo : '_altro';
            $grouped[$bucket][] = self::serializeDispositivoMappa($device);
        }

        return $grouped;
    }

    private static function serializeDispositivoMappa(Dispositivo $device): array
    {
        return [
            'id' => (int) $device->id,
            'nome' => (string) $device->nome,
            'tipo' => $device->tipo !== null ? (string) $device->tipo : null,
            'ubicazione' => $device->ubicazione !== null ? (string) $device->ubicazione : null,
            'is_attivo' => (bool) $device->is_attivo,
            'occupato' => (bool) $device->occupato,
            'attivita_id' => $device->attivita_id !== null ? (int) $device->attivita_id : null,
            'attivita_nome' => $device->attivita?->nome,
            'is_punto_vendita' => in_array($device->tipo, [
                Dispositivo::CASSA,
                Dispositivo::KIOSK,
                Dispositivo::CAMERIERE,
            ], true),
        ];
    }

    /**
     * Bozza mappa: contenitore = attività → punto vendita (cassa/kiosk/cameriere) + cucine → stampante.
     */
    public static function buildTopologyByAttivita(): array
    {
        $pvTipi = [Dispositivo::CASSA, Dispositivo::KIOSK, Dispositivo::CAMERIERE];

        $attivitaRows = Attivita::query()
            ->where('is_attiva', true)
            ->orderBy('nome')
            ->get(['id', 'nome']);

        $attivitaIds = $attivitaRows->pluck('id')->all();

        $devicesGrouped = Dispositivo::query()
            ->whereIn('attivita_id', $attivitaIds)
            ->orderBy('nome')
            ->get(['id', 'nome', 'ubicazione', 'tipo', 'is_attivo', 'attivita_id'])
            ->groupBy(fn (Dispositivo $d) => (int) $d->attivita_id);

        $cucineByAttivita = Cucina::query()
            ->whereIn('attivita_id', $attivitaIds)
            ->orderBy('nome')
            ->get(['id', 'nome', 'stampante_id', 'attivita_id'])
            ->groupBy(fn (Cucina $c) => (int) $c->attivita_id);

        $stampanteIds = Cucina::query()
            ->whereIn('attivita_id', $attivitaIds)
            ->whereNotNull('stampante_id')
            ->pluck('stampante_id')
            ->unique()
            ->filter()
            ->values();

        $stampanti = Dispositivo::query()
            ->whereIn('id', $stampanteIds)
            ->get(['id', 'nome', 'ubicazione', 'tipo', 'is_attivo'])
            ->keyBy('id');

        $serialize = static function (Dispositivo $d): array {
            $attrs = $d->getAttributes();
            $ip = null;
            if (array_key_exists('ip', $attrs) && $attrs['ip'] !== null) {
                $ip = (string) $attrs['ip'];
            }

            return [
                'id' => (int) $d->id,
                'nome' => (string) $d->nome,
                'ubicazione' => $d->ubicazione !== null ? (string) $d->ubicazione : null,
                'tipo' => $d->tipo !== null ? (string) $d->tipo : null,
                'is_attivo' => (bool) $d->is_attivo,
                'ip' => $ip,
            ];
        };

        $out = [];

        foreach ($attivitaRows as $att) {
            $aid = (int) $att->id;
            $devices = $devicesGrouped->get($aid, collect());
            $puntiVendita = $devices->whereIn('tipo', $pvTipi)->values()->map($serialize)->all();
            $altri = $devices->whereNotIn('tipo', $pvTipi)->values()->map($serialize)->all();

            $cucinePayload = [];
            foreach ($cucineByAttivita->get($aid, collect()) as $cucina) {
                $st = null;
                if ($cucina->stampante_id && $stampanti->has((int) $cucina->stampante_id)) {
                    $st = $serialize($stampanti->get((int) $cucina->stampante_id));
                } elseif ($cucina->stampante_id) {
                    $fallback = Dispositivo::query()->find((int) $cucina->stampante_id);
                    if ($fallback) {
                        $st = $serialize($fallback);
                    }
                }
                $cucinePayload[] = [
                    'id' => (int) $cucina->id,
                    'nome' => (string) $cucina->nome,
                    'stampante' => $st,
                ];
            }

            $out[] = [
                'id' => $aid,
                'nome' => (string) $att->nome,
                'punti_vendita' => $puntiVendita,
                'cucine' => $cucinePayload,
                'altri' => $altri,
            ];
        }

        $orphanDevices = Dispositivo::query()
            ->whereNull('attivita_id')
            ->orderBy('nome')
            ->get(['id', 'nome', 'ubicazione', 'tipo', 'is_attivo', 'attivita_id']);

        $orphanCucine = Cucina::query()
            ->whereNull('attivita_id')
            ->orderBy('nome')
            ->get(['id', 'nome', 'stampante_id', 'attivita_id']);

        if ($orphanDevices->isNotEmpty() || $orphanCucine->isNotEmpty()) {
            $orphanStampanteIds = $orphanCucine->pluck('stampante_id')->filter()->unique()->values();
            $orphanStampanti = Dispositivo::query()
                ->whereIn('id', $orphanStampanteIds)
                ->get(['id', 'nome', 'ubicazione', 'tipo', 'is_attivo'])
                ->keyBy('id');

            $cucineOrfane = [];
            foreach ($orphanCucine as $cucina) {
                $st = null;
                if ($cucina->stampante_id && $orphanStampanti->has((int) $cucina->stampante_id)) {
                    $st = $serialize($orphanStampanti->get((int) $cucina->stampante_id));
                } elseif ($cucina->stampante_id) {
                    $fb = Dispositivo::query()->find((int) $cucina->stampante_id);
                    if ($fb) {
                        $st = $serialize($fb);
                    }
                }
                $cucineOrfane[] = [
                    'id' => (int) $cucina->id,
                    'nome' => (string) $cucina->nome,
                    'stampante' => $st,
                ];
            }

            $out[] = [
                'id' => 0,
                'nome' => 'Senza attività',
                'punti_vendita' => $orphanDevices->whereIn('tipo', $pvTipi)->values()->map($serialize)->all(),
                'cucine' => $cucineOrfane,
                'altri' => $orphanDevices->whereNotIn('tipo', $pvTipi)->values()->map($serialize)->all(),
            ];
        }

        return $out;
    }
}
