<?php

namespace App\Models;

use App\Utils\TransporteUtils;

use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;
use League\Csv\CannotInsertRecord;
use League\Csv\Writer;

class Barrio extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'nombre',
    ];

    /**
     * La región a la que pertenece el barrio.
     */
    public function region(): BelongsTo
    {
        return $this->belongsTo(Region::class);
    }

    /**
     * Los pedidos que pertenecen al barrio.
     */
    public function pedidos(): HasMany
    {
        return $this->hasMany(Pedido::class);
    }

    public function crearPedido(string $nombre) : Pedido {
        return $this->pedidos()->create(['nombre' => $nombre]);
    }

    /**
     * Devuelve una query, para obtener el resultado agregarle ->get().
     * La query devuelve objetos con todos los atributos de un producto, seguidos
     * de la cantidad de ese producto pedida entre todos los pedidos del barrio y
     * el costo total de dicha cantidad.
     */
    public function productosPedidos() {
        return DB::table('productos')
            ->join('pedido_producto', 'productos.id', '=', 'pedido_producto.producto_id')
            ->join('pedidos', 'pedidos.id', '=', 'pedido_producto.pedido_id')
            ->where(['pedidos.barrio_id' => $this->id, 'pedidos.pagado' => true])
            ->select('productos.*',
                     DB::raw('SUM(pedido_producto.cantidad) as cantidad'),
                     DB::raw('SUM(pedido_producto.cantidad * productos.precio) as total'))
            ->groupBy('productos.id');
    }

    public function totalARecaudar() : float {
        return $this->pedidos()->where(['pagado' => true])->get()->sum(
            fn($p) => $p->totalATransferir()
        );
    }

    public function totalATransferir() : float {
        return $this->totalProductosConTransporte() + $this->totalBonosDeTransporte();
    }

    public function totalBonosDeTransporte() : int {
        return TransporteUtils::calcularTotal($this->totalProductosConTransporte());
    }

    public function totalProductosConTransporte(): float
    {
        return $this->totalProductosIf(fn($p) => $p->pagaTransporte());
    }

    private function totalProductosIf($predicado) : float {
        return $this->productosPedidos()->where($predicado)->get()->sum(
            fn($producto) => $producto->total
        );
    }

    /**
     * Los productos que pertenecen al barrio.
     */
    public function productos(): HasMany
    {
        return $this->hasMany(Producto::class);
    }

    public function exportarPedidoACsv() {
        if ($this->productosPedidos()->get()->isNotEmpty()) {
            $columnaProductos = $this->armarColumnaTotales();

            try {
                $writer = Writer::createFromPath(resource_path('csv/exports/'.$this->nombre.'.csv'), 'w');
                $writer->setDelimiter("|");
                $writer->setEnclosure("'");
                $writer->insertAll($columnaProductos);
                return true;
            } catch (CannotInsertRecord $e) {
                var_export($e->getRecords());
                return false;
            }
        }
        return false;
    }

    private function armarColumnaTotales() : array {
        $columnaProductos = [];
        $filasVaciasAgregadas = false;
        $productos = $this->productosPedidos()->where(['barrial' => false])->get();

        foreach (Categoria::orderBy('id')->get() as $categoria) {
            if ($categoria->productos()->where(['barrial' => false])->count() == 0)
                continue;

            $columnaProductos[] = ['nombre' => $categoria->nombre, 'cantidad' => null];

            if ($categoria->nombre == 'TRANSPORTE, BONOS Y FINANCIAMIENTO SORORO')
                $columnaProductos[] = ['nombre' => 'Bono de Transporte', 'cantidad' => TransporteUtils::cantidad($this->totalProductosConTransporte())];
            if ($categoria->nombre == 'PRODUCTOS DE GESTIÓN MENSTRUAL')
                $columnaProductos[] = ['nombre' => '¿Cuántas copas quieren y pueden comprar en el grupo?', 'cantidad' => null];

            foreach ($categoria->productos()->orderBy('id')->get() as $producto) {
                if ($producto->precio == 0 && !$filasVaciasAgregadas) {
                    $columnaProductos[] = ['nombre' => '¿Cuántas copas quieren adquirir a través del financiamiento sororo?', 'cantidad' => null];
                    $filasVaciasAgregadas = true;
                }
                $columnaProductos[] = ['nombre' => $producto->nombre, 'cantidad' => $this->cantidadPedida($producto->id, $productos)];
            }
        }

        return $columnaProductos;
    }

    private function cantidadPedida($productoId, $productos) {
        return $productos->find($productoId)->cantidad ?? 0;
    }
}