<?php

namespace App\Http\Controllers;

use App\Models\Restaurante;
use App\Models\Compra;
use App\Models\Proveedor;
use App\Models\Factura;
use App\Models\Ingrediente;
use App\Models\CompraIngrediente;
use App\Services\PaginatorService;
use App\Services\UuidService;
use App\Exceptions\GenericException;
use App\Exceptions\CantdeletehasChild;
use App\Exceptions\AlreadyExistsException;
use App\Exceptions\ModelNotFoundException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Ramsey\Uuid\Uuid;

class ComprasController extends Controller {

    /**
     * Obtiene de forma paginada las compras registradas en el backend
     */
    public function all(Request $request, $restaurante_id) {
        app(UuidService::class)->validOrFail($restaurante_id);
        $restaurante = Restaurante::findOrFail($restaurante_id);

        $compras = $restaurante->compras();

        $paginate = app(PaginatorService::class)->paginate(
            perPage: $request->input('per_page', 15),
            page: $request->input('page', 1),
            total: $compras->count(),
            route: 'compras.all',
            data: ['restaurante_id' => $restaurante_id]
        );

        $data = $compras->get()
                         ->skip($paginate['from'] - 1)
                         ->take($paginate['per_page'])
                         ->all();

        return response()->json([
            'pagination' => $paginate,
            'data' => $data
        ]);
    }

    /**
     * Obtiene una compra por su id
     */
    public function get(Request $request, $restaurante_id, $id) {
        app(UuidService::class)->validOrFail($restaurante_id);
        app(UuidService::class)->validOrFail($id);

        $restaurante = Restaurante::findOrFail($restaurante_id);
        $compra = Compra::findOrFail($id);

        if($compra->restaurante != $restaurante) {
            throw new ModelNotFoundException("compra", $id);
        }

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

    /**
     * Crea una nueva compra
     */
    public function create(Request $request, $restaurante_id) {
        $this->validate($request, [
            'fecha_compra' => 'required|date',
            'en_arqueo' => 'required|boolean',
            'proveedor_id' => 'required'
        ]);

        app(UuidService::class)->validOrFail($restaurante_id);
        app(UuidService::class)->validOrFail($request->input('proveedor_id'));

        $restaurante = Restaurante::findOrFail($restaurante_id);
        $proveedor = Proveedor::findOrFail($request->input('proveedor_id'));

        if($proveedor->restaurante != $restaurante) {
          throw new ModelNotFoundException("proveedor", $request->input('proveedor_id'));
        }

        $compra = Compra::create([
            'id' => Uuid::uuid4(),
            'fecha_compra' => $request->input('fecha_compra'),
            'proveedor_id' => $proveedor->id,
            'en_arqueo' => $request->input('en_arqueo'),
            'restaurante_id' => $restaurante->id
        ]);

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

    /**
     * Actualiza una compra
     */
    public function update(Request $request, $restaurante_id, $id) {
        $this->validate($request, [
            'fecha_compra' => 'required|date',
            'en_arqueo' => 'required|boolean',
            'proveedor_id' => 'required'
        ]);

        app(UuidService::class)->validOrFail($restaurante_id);
        app(UuidService::class)->validOrFail($id);
        app(UuidService::class)->validOrFail($request->input('proveedor_id'));

        $restaurante = Restaurante::findOrFail($restaurante_id);
        $proveedor = Proveedor::findOrFail($request->input('proveedor_id'));
        $compra = Compra::findOrFail($id);

        if($proveedor->restaurante != $restaurante) {
            throw new ModelNotFoundException("proveedor", $proveedor->id);
        }

        if($compra->restaurante != $restaurante) {
            throw new ModelNotFoundException("compra", $compra->id);
        }

        $compra->fecha_compra= $request->input('fecha_compra');
        $compra->en_arqueo = $request->input('en_arqueo');
        $compra->proveedor_id = $proveedor->id;
        $compra->save();

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

    /**
     * Elimina una compra
     */
    public function delete(Request $request, $restaurante_id, $id) {
        app(UuidService::class)->validOrFail($restaurante_id);
        app(UuidService::class)->validOrFail($id);

        $restaurante = Restaurante::findOrFail($restaurante_id);
        $compra = Compra::findOrFail($id);

        if($compra->restaurante != $restaurante) {
            throw new ModelNotFoundException("compra", $id);
        }

        $compra->ingredientes()->delete();
        $compra->facturas()->delete();

        $compra->delete();

        return response()->json([], 204);
    }

    /**
     * Obtiene los ingredientes de una compra
     */
    public function getIngredientes(Request $request, $restaurante_id, $id) {
        app(UuidService::class)->validOrFail($restaurante_id);
        app(UuidService::class)->validOrFail($id);

        $restaurante = Restaurante::findOrFail($restaurante_id);
        $compra = Compra::findOrFail($id);

        if($compra->restaurante != $restaurante) {
            throw new ModelNotFoundException("compra", $id);
        }

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

    /**
     * Agrega un ingrediente a una compra
     */
    public function addIngrediente(Request $request, $restaurante_id, $id, $ingrediente_id) {
        $this->validate($request, [
            'unidades' => 'required|numeric',
            'monto_unitario' => 'required|numeric'
        ]);

        app(UuidService::class)->validOrFail($restaurante_id);
        app(UuidService::class)->validOrFail($id);
        app(UuidService::class)->validOrFail($ingrediente_id);

        $restaurante = Restaurante::findOrFail($restaurante_id);
        $compra = Compra::findOrFail($id);
        $ingrediente = Ingrediente::findOrFail($ingrediente_id);

        if($compra->restaurante != $restaurante) {
          throw new ModelNotFoundException("compra", $compra->id);
        }

        if($ingrediente->restaurante != $restaurante) {
          throw new ModelNotFoundException("ingrediente", $ingrediente->id);
        }

        foreach($compra->ingredientes as $ci){
            if($ci->ingrediente->id == $ingrediente->id) {
                throw new AlreadyExistsException("ingrediente");
            }
        }

        $compraIngrediente = CompraIngrediente::create([
            'id' => Uuid::uuid4(),
            'unidades' => $request->input('unidades'),
            'monto_unitario' => $request->input('monto_unitario'),
            'compra_id' => $compra->id,
            'ingrediente_id' => $ingrediente->id
        ]);

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

    /**
     * Elimina un ingrediente de una compra
     */
    public function deleteIngrediente(Request $request, $restaurante_id, $id, $ingrediente_id) {
        app(UuidService::class)->validOrFail($restaurante_id);
        app(UuidService::class)->validOrFail($id);
        app(UuidService::class)->validOrFail($ingrediente_id);

        $restaurante = Restaurante::findOrFail($restaurante_id);
        $compra = Compra::findOrFail($id);
        $ingrediente = Ingrediente::findOrFail($ingrediente_id);

        if($compra->restaurante != $restaurante) {
          throw new ModelNotFoundException("compra", $compra->id);
        }

        if($ingrediente->restaurante != $restaurante) {
          throw new ModelNotFoundException("ingrediente", $ingrediente->id);
        }

        $toDelete = CompraIngrediente::where('compra_id', $compra->id)->where('ingrediente_id', $ingrediente->id);

        if($toDelete->count() == 0) { 
          throw new ModelNotFoundException("compra_ingrediente", null);
        }

        $toDelete->delete();

        return response()->json([], 204);
    }
}
