<?php

namespace App\Services\Paga;

use App\Models\MetodoPagamento;
use App\Models\Ordine;
use App\Models\Pagamento;
use RuntimeException;
use Throwable;

class RegistraPagamento
{
    /** @var array<string, callable> */
    private array $handlers;

    public function __construct()
    {
        $this->handlers = [
            MetodoPagamento::CONTANTI => fn (Pagamento $pagamento, Ordine $ordine, array $context) =>
                app(Contanti::class)->paga($pagamento),

            MetodoPagamento::POS => fn (Pagamento $pagamento, Ordine $ordine, array $context) =>
                app(Pos::class)->paga($pagamento),

            MetodoPagamento::SEGRESTA_WALLET => fn (Pagamento $pagamento, Ordine $ordine, array $context) =>
                app(SegrestaWallet::class)->registraMovimento(
                    $pagamento,
                    'uscita',
                    (float) $ordine->prezzo,
                    (string) ($context['causale'] ?? ('Pagamento ordine #' . $ordine->id)),
                    $context['tag_id'] ?? null
                ),
        ];
    }

    public function esegui(Ordine $ordine, Pagamento $pagamento, array $context = []): array
    {
        $tipo = (string) $pagamento->metodo_pagamento->tipo;

        if (! isset($this->handlers[$tipo])) {
            return ['result' => false, 'message' => 'Metodo pagamento non supportato.'];
        }

        try {
            $result = ($this->handlers[$tipo])($pagamento, $ordine, $context);
        } catch (Throwable $e) {
            $result = ['result' => false, 'message' => $e->getMessage()];
        }

        if (($result['result'] ?? false) === true) {
            $pagamento->stato = Pagamento::PAGATO;
            $ordine->stato = Ordine::PAGATO;
        } else {
            $pagamento->stato = Pagamento::ERRORE;
            $ordine->stato = Ordine::CARRELLO;
        }

        $pagamento->save();
        $ordine->save();

        return [
            'result' => (bool) ($result['result'] ?? false),
            'message' => (string) ($result['message'] ?? 'Esito pagamento non disponibile.'),
        ];
    }
}