<?php

namespace App\Http\Controllers;

use App\Models\Cliente;
use App\Models\ManyChatCarrito;
use App\Models\ManyChatCarritoItem;
use App\Models\ManyChatIntegracion;
use App\Models\ManyChatLog;
use App\Models\ManyChatPedido;
use App\Models\ManyChatPedidoDetalle;
use App\Models\Producto;
use App\Services\ManyChatResponseService;
use App\Services\ProductSearchService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;

class ManyChatApiController extends Controller
{
    public function __construct(
        private readonly ProductSearchService $searchService,
        private readonly ManyChatResponseService $responseService,
    ) {}

    /**
     * GET /api/manychat/productos/buscar?query=arroz
     */
    public function buscarProducto(Request $request): JsonResponse
    {
        $empresaId = (int) $request->attributes->get('manychat_empresa_id');
        $query = trim((string) $request->query('query', ''));
        $startTime = microtime(true);

        if ($query === '') {
            $response = ['success' => false, 'message' => 'El parámetro "query" es requerido.', 'data' => null];
            $this->log($empresaId, '/productos/buscar', $query, $request->all(), $response, 422, $request->ip());
            return response()->json($response, 422);
        }

        $products = $this->searchService->search($empresaId, $query);

        if ($products->isEmpty()) {
            $response = $this->responseService->productNotFound($query, $empresaId);
            $this->log($empresaId, '/productos/buscar', $query, ['query' => $query], $response, 200, $request->ip());
            return response()->json($response);
        }

        $response = $products->count() === 1
            ? $this->responseService->productFound($products->first(), $empresaId)
            : $this->responseService->multipleProducts($products, $empresaId);

        $this->log($empresaId, '/productos/buscar', $query, ['query' => $query], $response, 200, $request->ip());

        return response()->json($response);
    }

    /**
     * GET /api/manychat/productos/stock?query=arroz
     */
    public function stockProducto(Request $request): JsonResponse
    {
        $empresaId = (int) $request->attributes->get('manychat_empresa_id');
        $query = trim((string) $request->query('query', ''));

        if ($query === '') {
            $response = ['success' => false, 'message' => 'El parámetro "query" es requerido.', 'data' => null];
            return response()->json($response, 422);
        }

        ['product' => $product, 'stock_por_sucursal' => $stock] = $this->searchService->stockPorSucursal($empresaId, $query);

        if ($product === null) {
            $response = $this->responseService->productNotFound($query, $empresaId);
            $this->log($empresaId, '/productos/stock', $query, ['query' => $query], $response, 200, $request->ip());
            return response()->json($response);
        }

        $response = $this->responseService->stockResponse($product, $stock);
        $this->log($empresaId, '/productos/stock', $query, ['query' => $query], $response, 200, $request->ip());

        return response()->json($response);
    }

    /**
     * POST /api/manychat/leads
     */
    public function storeLead(Request $request): JsonResponse
    {
        $empresaId = (int) $request->attributes->get('manychat_empresa_id');

        $validator = Validator::make($request->all(), [
            'nombre' => 'required|string|max:160',
            'telefono' => 'nullable|string|max:30',
            'producto_interes' => 'nullable|string|max:200',
            'origen' => 'nullable|string|max:80',
        ]);

        if ($validator->fails()) {
            $response = ['success' => false, 'message' => implode(' ', $validator->errors()->all()), 'data' => null];
            return response()->json($response, 422);
        }

        $nombre = trim((string) $request->input('nombre'));
        $telefono = trim((string) $request->input('telefono', ''));

        $cliente = Cliente::updateOrCreate(
            ['empresa_id' => $empresaId, 'telefono' => $telefono ?: null],
            [
                'nombre' => $nombre,
                'telefono' => $telefono ?: null,
                'activo' => true,
            ]
        );

        $response = $this->responseService->leadCreated($nombre);
        $response['data'] = ['cliente_id' => $cliente->id];

        $this->log($empresaId, '/leads', null, $request->except([]), $response, 201, $request->ip());

        return response()->json($response, 201);
    }

    /**
     * POST /api/manychat/pedidos
     */
    public function storePedido(Request $request): JsonResponse
    {
        $empresaId = (int) $request->attributes->get('manychat_empresa_id');

        $validator = Validator::make($request->all(), [
            'cliente_nombre' => 'required|string|max:160',
            'telefono' => 'nullable|string|max:30',
            'productos' => 'required|array|min:1|max:20',
            'productos.*.producto_id' => 'required|integer|min:1',
            'productos.*.cantidad' => 'required|numeric|min:0.01',
            'direccion' => 'nullable|string|max:500',
            'observaciones' => 'nullable|string|max:500',
        ]);

        if ($validator->fails()) {
            $response = ['success' => false, 'message' => implode(' ', $validator->errors()->all()), 'data' => null];
            return response()->json($response, 422);
        }

        $productosInput = (array) $request->input('productos', []);
        $productoIds = array_column($productosInput, 'producto_id');

        // Load and validate all products belong to this empresa
        $productos = Producto::query()
            ->where('empresa_id', $empresaId)
            ->where('activo', 1)
            ->whereIn('id', $productoIds)
            ->get()
            ->keyBy('id');

        $foundIds = $productos->keys()->all();
        $missingIds = array_diff($productoIds, $foundIds);

        if (! empty($missingIds)) {
            $response = [
                'success' => false,
                'message' => 'Algunos productos no existen o no pertenecen a esta empresa: '.implode(', ', $missingIds),
                'data' => null,
            ];
            return response()->json($response, 422);
        }

        $pedido = DB::transaction(function () use ($empresaId, $request, $productosInput, $productos): ManyChatPedido {
            $total = 0.0;

            $pedido = ManyChatPedido::create([
                'empresa_id' => $empresaId,
                'cliente_nombre' => trim((string) $request->input('cliente_nombre')),
                'telefono' => trim((string) $request->input('telefono', '')) ?: null,
                'direccion' => trim((string) $request->input('direccion', '')) ?: null,
                'observaciones' => trim((string) $request->input('observaciones', '')) ?: null,
                'total' => 0,
                'estado' => 'pendiente',
                'origen' => 'whatsapp_manychat',
            ]);

            foreach ($productosInput as $item) {
                $productoId = (int) ($item['producto_id'] ?? 0);
                $cantidad = (float) ($item['cantidad'] ?? 1);
                /** @var Producto $producto */
                $producto = $productos[$productoId];
                $precioUnitario = (float) $producto->precio_venta;
                $subtotal = $precioUnitario * $cantidad;
                $total += $subtotal;

                ManyChatPedidoDetalle::create([
                    'pedido_id' => $pedido->id,
                    'producto_id' => $productoId,
                    'producto_nombre' => $producto->nombre,
                    'precio_unitario' => $precioUnitario,
                    'cantidad' => $cantidad,
                    'subtotal' => $subtotal,
                ]);
            }

            $pedido->update(['total' => $total]);

            return $pedido->fresh();
        });

        $totalFormateado = number_format((float) $pedido->total, 0, ',', '.');
        $response = $this->responseService->pedidoCreado(
            $pedido->id,
            $pedido->cliente_nombre,
            $totalFormateado
        );

        $this->log($empresaId, '/pedidos', null, $request->except([]), $response, 201, $request->ip());

        return response()->json($response, 201);
    }

    /**
     * POST /api/manychat/carrito/agregar
     */
    public function agregarCarrito(Request $request): JsonResponse
    {
        $empresaId = (int) $request->attributes->get('manychat_empresa_id');

        $validator = Validator::make($request->all(), [
            'session_id' => 'required|string|max:160',
            'producto_id' => 'required|integer|min:1',
            'cantidad' => 'required|numeric|min:0.01|max:9999',
        ]);

        if ($validator->fails()) {
            $response = ['success' => false, 'message' => implode(' ', $validator->errors()->all()), 'data' => null];
            return response()->json($response, 422);
        }

        $sessionId = trim((string) $request->input('session_id'));
        $productoId = (int) $request->input('producto_id');
        $cantidad = (float) $request->input('cantidad');

        $producto = Producto::query()
            ->where('empresa_id', $empresaId)
            ->where('activo', 1)
            ->find($productoId);

        if (! $producto) {
            $response = [
                'success' => false,
                'message' => 'El producto no existe o no pertenece a esta empresa.',
                'data' => null,
            ];
            return response()->json($response, 422);
        }

        [$carrito, $item] = DB::transaction(function () use ($empresaId, $sessionId, $producto, $cantidad): array {
            $carrito = $this->activeCart($empresaId, $sessionId, true);

            $precioUnitario = (float) $producto->precio_venta;
            $item = ManyChatCarritoItem::query()->firstOrNew([
                'carrito_id' => $carrito->id,
                'producto_id' => $producto->id,
            ]);

            $item->producto_nombre = $producto->nombre;
            $item->precio_unitario = $precioUnitario;
            $item->cantidad = (float) ($item->exists ? $item->cantidad : 0) + $cantidad;
            $item->subtotal = $item->cantidad * $precioUnitario;
            $item->save();

            $carrito->last_activity_at = now();
            $carrito->save();

            $this->recalculateCart($carrito);

            return [$carrito->fresh(), $item->fresh()];
        });

        $response = $this->responseService->cartItemAdded($carrito, $item);
        $this->log($empresaId, '/carrito/agregar', null, $request->except([]), $response, 200, $request->ip());

        return response()->json($response);
    }

    /**
     * GET /api/manychat/carrito?session_id=...
     */
    public function verCarrito(Request $request): JsonResponse
    {
        $empresaId = (int) $request->attributes->get('manychat_empresa_id');
        $sessionId = trim((string) $request->query('session_id', ''));

        if ($sessionId === '') {
            $response = ['success' => false, 'message' => 'El parámetro "session_id" es requerido.', 'data' => null];
            return response()->json($response, 422);
        }

        $carrito = $this->activeCart($empresaId, $sessionId);

        if (! $carrito || $carrito->items->isEmpty()) {
            $response = $this->responseService->cartEmpty();
            $this->log($empresaId, '/carrito', null, ['session_id' => $sessionId], $response, 200, $request->ip());
            return response()->json($response);
        }

        $response = $this->responseService->cartSummary($carrito);
        $this->log($empresaId, '/carrito', null, ['session_id' => $sessionId], $response, 200, $request->ip());

        return response()->json($response);
    }

    /**
     * POST /api/manychat/carrito/limpiar
     */
    public function limpiarCarrito(Request $request): JsonResponse
    {
        $empresaId = (int) $request->attributes->get('manychat_empresa_id');

        $validator = Validator::make($request->all(), [
            'session_id' => 'required|string|max:160',
        ]);

        if ($validator->fails()) {
            $response = ['success' => false, 'message' => implode(' ', $validator->errors()->all()), 'data' => null];
            return response()->json($response, 422);
        }

        $sessionId = trim((string) $request->input('session_id'));
        $carrito = $this->activeCart($empresaId, $sessionId);

        if ($carrito) {
            DB::transaction(function () use ($carrito): void {
                $carrito->items()->delete();
                $carrito->update([
                    'total' => 0,
                    'last_activity_at' => now(),
                ]);
            });
        }

        $response = $this->responseService->cartCleared();
        $this->log($empresaId, '/carrito/limpiar', null, $request->except([]), $response, 200, $request->ip());

        return response()->json($response);
    }

    /**
     * POST /api/manychat/carrito/confirmar
     */
    public function confirmarCarrito(Request $request): JsonResponse
    {
        $empresaId = (int) $request->attributes->get('manychat_empresa_id');

        $validator = Validator::make($request->all(), [
            'session_id' => 'required|string|max:160',
            'cliente_nombre' => 'required|string|max:160',
            'telefono' => 'nullable|string|max:30',
            'direccion' => 'nullable|string|max:500',
            'observaciones' => 'nullable|string|max:500',
        ]);

        if ($validator->fails()) {
            $response = ['success' => false, 'message' => implode(' ', $validator->errors()->all()), 'data' => null];
            return response()->json($response, 422);
        }

        $sessionId = trim((string) $request->input('session_id'));
        $carrito = $this->activeCart($empresaId, $sessionId);

        if (! $carrito || $carrito->items->isEmpty()) {
            $response = ['success' => false, 'message' => 'No hay productos en el carrito para confirmar.', 'data' => null];
            return response()->json($response, 422);
        }

        $pedido = DB::transaction(function () use ($request, $carrito, $empresaId): ManyChatPedido {
            $carrito->fill([
                'cliente_nombre' => trim((string) $request->input('cliente_nombre')),
                'telefono' => trim((string) $request->input('telefono', '')) ?: null,
                'direccion' => trim((string) $request->input('direccion', '')) ?: null,
                'observaciones' => trim((string) $request->input('observaciones', '')) ?: null,
                'last_activity_at' => now(),
            ]);
            $carrito->save();

            $pedido = ManyChatPedido::create([
                'empresa_id' => $empresaId,
                'cliente_nombre' => (string) $carrito->cliente_nombre,
                'telefono' => $carrito->telefono,
                'direccion' => $carrito->direccion,
                'observaciones' => $carrito->observaciones,
                'total' => (float) $carrito->total,
                'estado' => 'pendiente',
                'origen' => 'whatsapp_manychat_carrito',
            ]);

            foreach ($carrito->items as $item) {
                ManyChatPedidoDetalle::create([
                    'pedido_id' => $pedido->id,
                    'producto_id' => $item->producto_id,
                    'producto_nombre' => $item->producto_nombre,
                    'precio_unitario' => (float) $item->precio_unitario,
                    'cantidad' => (float) $item->cantidad,
                    'subtotal' => (float) $item->subtotal,
                ]);
            }

            $carrito->update([
                'estado' => 'confirmado',
                'pedido_id' => $pedido->id,
                'confirmed_at' => now(),
                'last_activity_at' => now(),
            ]);

            return $pedido->fresh();
        });

        $response = $this->responseService->cartConfirmed($pedido);
        $this->log($empresaId, '/carrito/confirmar', null, $request->except([]), $response, 201, $request->ip());

        return response()->json($response, 201);
    }

    private function log(
        int $empresaId,
        string $endpoint,
        ?string $query,
        array $requestPayload,
        array $responsePayload,
        int $statusCode,
        ?string $ip
    ): void {
        try {
            ManyChatLog::registrar($empresaId, $endpoint, $query, $requestPayload, $responsePayload, $statusCode, $ip);
        } catch (\Throwable) {
            // Log failure must never break the API response
        }
    }

    private function activeCart(int $empresaId, string $sessionId, bool $create = false): ?ManyChatCarrito
    {
        $query = ManyChatCarrito::query()
            ->with('items')
            ->where('empresa_id', $empresaId)
            ->where('session_id', $sessionId)
            ->where('estado', 'activo')
            ->latest('id');

        if (! $create) {
            return $query->first();
        }

        return $query->first() ?? ManyChatCarrito::create([
            'empresa_id' => $empresaId,
            'session_id' => $sessionId,
            'estado' => 'activo',
            'last_activity_at' => now(),
            'total' => 0,
        ]);
    }

    private function recalculateCart(ManyChatCarrito $carrito): void
    {
        $total = (float) $carrito->items()->sum('subtotal');
        $carrito->update([
            'total' => $total,
            'last_activity_at' => now(),
        ]);
    }
}
