<?php
declare(strict_types=1);

namespace App\Service\ApiResourceBuilder\Dolibarr;

use App\ApiResources\Dolibarr\DolibarrAccount;
use App\ApiResources\Dolibarr\DolibarrBill;
use App\ApiResources\Dolibarr\DolibarrContract;
use App\ApiResources\Dolibarr\DolibarrContractLine;
use App\Service\Dolibarr\DolibarrApiService;

class DolibarrAccountBuilder
{
    public const PRODUCT_MAPPING = [
        1 => 'PRODUCT_ARTIST',   # OT Artist
        2 => 'PRODUCT_ARTIST_PREMIUM',   # OT Artist Premium
        3 => 'PRODUCT_SCHOOL',   # OT School Standard
        4 => 'PRODUCT_SCHOOL_PREMIUM',   # OT School Premium
        5 => 'PRODUCT_MANAGER',   # OT Manager
    ];

    public function __construct(
        private DolibarrApiService $dolibarrApiService,
    )
    {}

    public function getDolibarrAccount(int $id): DolibarrAccount {

        // Get dolibarr account (society)
        $accountData = $this->dolibarrApiService->getSociety($id);
        $dolibarrAccount = $this->createDolibarrAccount($id, $accountData);

        if ($dolibarrAccount->getSocId() === null) {
            return $dolibarrAccount;
        }

        // Get active contract and services
        $contractData = $this->dolibarrApiService->getActiveContract($dolibarrAccount->getSocId());

        if ($contractData !== null) {
            $contract = $this->createDolibarrContract($contractData);
            $dolibarrAccount->setContract($contract);
        }

        // get bills
        $billsData = $this->dolibarrApiService->getBills($dolibarrAccount->getSocId());
        foreach ($billsData as $billData) {
            $bill = $this->createDolibarrBill($billData);
            $dolibarrAccount->addBill($bill);
        }

        return $dolibarrAccount;
    }

    /**
     * @param int $organizationId
     * @param array<mixed>|null $accountData
     * @return DolibarrAccount
     */
    public function createDolibarrAccount(int $organizationId, ?array $accountData): DolibarrAccount {
        $dolibarrAccount = new DolibarrAccount();
        $dolibarrAccount->setOrganizationId($organizationId);
        if ($accountData === null) {
            return $dolibarrAccount;
        }

        $dolibarrAccount->setSocId((int)$accountData['id'])
                        ->setClientNumber($accountData['code_client']);

        if (
            array_key_exists('options_2iopen_software_used', $accountData['array_options']) &&
            !empty($accountData['array_options']['options_2iopen_software_used'])
        ) {
            $dolibarrAccount->setProduct(
                self::PRODUCT_MAPPING[(int)$accountData['array_options']['options_2iopen_software_used']]
            );
        }
        return $dolibarrAccount;
    }

    /**
     * @param array<mixed> $contractData
     * @return DolibarrContract
     */
    public function createDolibarrContract(array $contractData): DolibarrContract {
        $contract = new DolibarrContract();
        $contract->setRef($contractData['ref'] ?? '')
                 ->setSocId((int)$contractData['socid']);

        foreach ($contractData['lines'] as $lineData) {
            $line = $this->createDolibarrContractLine($lineData);
            $contract->addLine($line);
        }

        return $contract;
    }

    /**
     * @param array<mixed> $lineData
     * @return DolibarrContractLine
     * @throws \Exception
     */
    public function createDolibarrContractLine(array $lineData): DolibarrContractLine {
        $line = new DolibarrContractLine();
        return $line->setId((int)$lineData['id'])
                    ->setContractId((int)$lineData['fk_contrat'])
                    ->setServiceRef($lineData['product_ref'])
                    ->setServiceLabel($lineData['product_label'])
                    ->setDateStart(new \DateTime(date('c', (int)$lineData['date_start'])))
                    ->setDateEnd(new \DateTime(date('c', (int)$lineData['date_end'])));
    }

    /**
     * @param array<mixed> $billData
     * @return DolibarrBill
     * @throws \Exception
     */
    public function createDolibarrBill(array $billData): DolibarrBill {
        $bill = new DolibarrBill();
        return $bill->setId((int)$billData['id'])
                    ->setRef($billData['ref'])
                    ->setTaxExcludedAmount((float)$billData['total_ht'])
                    ->setTaxIncludedAmount((float)$billData['total_ttc'])
                    ->setDate(new \DateTime(date('c', (int)$billData['date'])))
                    ->setPaid((bool)$billData['paye']);
    }
}
