<?php

namespace App\Modules\CashMovementFactReceipt\Application\GenerateProduct;

use App\Modules\CashMovementFactReceipt\Domain\CashMovementFactReceiptRepository;
use App\Modules\FactProduct\Domain\FactProduct;
use App\Modules\FactProduct\Domain\FactProductCode;
use App\Modules\FactProduct\Domain\FactProductIdProduct;
use App\Modules\FactProduct\Domain\FactProductName;
use App\Modules\FactProduct\Domain\FactProductStatus;
use App\Modules\FactProduct\Domain\IdFactProduct;
use App\Modules\FactReceipt\Domain\IdFactReceipt;
use App\Modules\FactReceiptDetail\Domain\FactReceiptDetail;
use App\Modules\FactReceiptDetail\Domain\FactReceiptDetailAmount;
use App\Modules\FactReceiptDetail\Domain\FactReceiptDetailDiscount;
use App\Modules\FactReceiptDetail\Domain\FactReceiptDetailStatus;
use App\Modules\FactReceiptDetail\Domain\FactReceiptDetailTotal;
use App\Modules\FactReceiptDetail\Domain\FactReceiptDetailUnitPrice;
use App\Modules\FactReceiptDetail\Domain\IdFactReceiptDetail;
use App\Modules\FactTypeOperation\Domain\IdFactTypeOperation;
use App\Modules\FactUnit\Domain\IdFactUnit;
use App\Modules\Shared\Domain\Data\DataGroup;
use App\Modules\Shared\Domain\Data\DataGroupCollection;
use App\Modules\Shared\Domain\Data\DataGroupGenerator;

final class CashMovementFactReceiptProductGenerator
{
    public function __construct(
        private CashMovementFactReceiptRepository $repository,
        private DataGroupGenerator $generator
    ) {
    }

    public function __invoke(array $bookingTourPassenger, $idFactReceipt)
    {
        $collection = $this->generateGroups($bookingTourPassenger);
        return $this->generateElements($collection, $idFactReceipt);
    }

    public function generateElements(DataGroupCollection $collection, $idFactReceipt)
    {
        return array_map(fn ($data) => [
            $this->generateProduct($data),
            $this->generateDetail($data, $idFactReceipt)
        ], array_values($collection->data()));
    }

    public function generateGroups($bookingTourPassenger)
    {
        $items = $this->packBy('BookingTour_Group', 'Id_Passenger', $bookingTourPassenger);
        return $this->generator->groupBy('BookingTour_Group', $items);
    }

    public function packBy($first, $second, $elements)
    {
        $elementList = [];
        foreach ($elements as $element) {
            if (!isset($elementList[$element->$first])) {
                $elementList[$element->$first] = [];
            }
            if (!isset($elementList[$element->$first][$element->$second])) {
                $elementList[$element->$first][$element->$second] = $element;
            }
        }

        $turn = [];
        foreach ($elementList as $element) {
            foreach ($element as $item) {
                $turn[] = $item;
            }
        }
        return $turn;
    }

    public function generateProduct(DataGroup $group)
    {
        return new FactProduct(
            new IdFactProduct(0),
            new FactProductCode($group->element->Package_Name . '_' . $group->element->Id_CashMovement),
            new FactProductName($this->generateProductName($group)),
            new FactProductIdProduct(''),
            new FactProductStatus(FactProductStatus::ACTIVE)
        );
    }

    public function generateProductName(DataGroup $collection)
    {
        return $collection->element->Package_Name
            . "\n"
            . implode("\n", array_map(fn ($e) => $e->Passenger_Name . ' ' . $e->Passenger_LastName, $collection->list));
    }

    public function generateDetail(DataGroup $group, $idFactReceipt)
    {
        return new FactReceiptDetail(
            new IdFactReceiptDetail(0),
            new FactReceiptDetailAmount(1),
            new FactReceiptDetailUnitPrice($group->element->CashMovementDetail_Amount),
            new FactReceiptDetailDiscount(0),
            new FactReceiptDetailTotal(0),
            new FactReceiptDetailStatus(FactReceiptDetailStatus::ACTIVE),
            new IdFactProduct(0),
            new IdFactTypeOperation(IdFactTypeOperation::defaultValue()),
            new IdFactUnit(IdFactUnit::defaultValue()),
            new IdFactReceipt($idFactReceipt),
        );
    }
}
