<?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]);
    }

    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->totalNoBarriales() + $this->totalBonosDeTransporte();
    }

    public function totalNoBarriales() {
        return $this->totalProductosIf(['barrial' => false]);
    }

    public function totalBarriales() {
        return $this->totalProductosIf(['barrial' => true]);
    }

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

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

    /**
     * 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;
            }
        }
    }

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

        foreach (Categoria::orderBy('id')->get() as $keyC => $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' => $this->totalBonosDeTransporte()];
            else 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 $keyP => $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->first(fn($p) => $p->id == $productoId)->cantidad ?? 0;
    }
}