<?php

declare(strict_types=1);

namespace Maestro\Core\Modules\Offers\Services;

use Illuminate\Support\Facades\Storage;
use Maestro\Core\Models\MaestroAppSetting;
use Maestro\Core\Models\Organization;
use Maestro\Core\Modules\Offers\Models\Offer;
use Maestro\Core\Support\MaestroAppSettingsPresenter;

final class OfferDocumentBuilder
{
    /**
     * @return array<string, mixed>
     */
    public static function build(Offer $offer): array
    {
        $offer->loadMissing(['customer', 'contactPerson', 'sections.rows.catalogItem']);

        $organization = Organization::instance();
        $totals = OfferTotalsService::summarize($offer);
        $app = MaestroAppSettingsPresenter::toArray(MaestroAppSetting::instance());

        return [
            'offer_number' => $offer->offer_number,
            'subject' => $offer->subject,
            'intro_html' => $offer->intro_html,
            'status' => $offer->status?->value,
            'valid_until' => optional($offer->valid_until)?->format('Y-m-d'),
            'issued_on' => $offer->created_at?->toDateString(),
            'signer_name' => $offer->signer_name,
            'signature_url' => self::signatureUrl($offer->signature_path),

            'customer' => $offer->customer ? [
                'name' => $offer->customer->name,
                'email' => $offer->customer->email,
                'phone' => $offer->customer->phone,
            ] : null,

            'contact' => self::contactBlock($offer),

            'sender' => $organization ? self::senderBlock($organization) : [],

            'logo_url' => $app['logos']['header'],

            'sections' => $offer->sections->map(function ($section): array {
                $rowsOut = [];

                foreach ($section->rows as $row) {
                    [$net, $vatLine] = OfferTotalsService::lineAmounts($row);
                    $rowsOut[] = [
                        'description_html' => $row->description_html,
                        'pricing_type' => $row->pricing_type?->value,
                        'pricing_label' => OfferTotalsService::pricingLabel($row->pricing_type),
                        'custom_unit_label' => $row->custom_unit_label,
                        'quantity' => (float) $row->quantity,
                        'unit_price' => (float) $row->unit_price,
                        'vat_rate' => (float) $row->vat_rate,
                        'line_net_total' => $net,
                        'line_vat' => $vatLine,
                        'discount_type' => $row->discount_type?->value,
                        'discount_value' => (float) $row->discount_value,
                    ];
                }

                return [
                    'title' => $section->title,
                    'description_html' => $section->description_html,
                    'rows' => $rowsOut,
                ];
            })->values()->all(),

            'totals' => $totals,
        ];
    }

    /** @param  Offer  $offer  model with contact relation */
    private static function contactBlock(Offer $offer): ?array
    {
        $c = $offer->contactPerson;

        return $c ? [
            'name' => trim($c->first_name.' '.$c->last_name),
            'email' => $c->email,
            'phone' => $c->phone,
        ] : null;
    }

    /**
     * @return array<string, string|null>
     */
    private static function senderBlock(Organization $org): array
    {
        $line1 = trim(implode(' ', array_filter([(string) $org->street, (string) $org->house_number])));
        $line2Parts = [$org->postal_code, $org->city, $org->country];
        $line2 = trim(implode(' ', array_filter($line2Parts)));

        return [
            'legal_name' => $org->display_name,
            'address_line_1' => $line1 !== '' ? $line1 : (string) $org->address_line_1,
            'address_line_2' => $line2 !== '' ? $line2 : trim((string) $org->address_line_2),
            'vat_number' => $org->vat_number,
            'iban' => $org->iban,
            'email' => $org->email,
            'phone' => $org->phone,
            'invoice_email' => $org->invoice_email,
            'website' => $org->website,
        ];
    }

    private static function signatureUrl(?string $path): ?string
    {
        if ($path === null || $path === '') {
            return null;
        }

        return Storage::disk('public')->url($path);
    }
}
