<?php

declare(strict_types=1);

function invoice_pdf_colors(): array
{
    return [
        'gold' => [176, 155, 113],
        'navy' => [28, 48, 88],
        'table_header' => [238, 244, 250],
        'table_header_text' => [102, 102, 102],
        'table_accent' => [190, 210, 230],
        'text' => [102, 102, 102],
        'body' => [102, 102, 102],
        'muted' => [110, 110, 110],
        'meta' => [110, 110, 110],
        'row_alt' => [246, 249, 252],
        'white' => [255, 255, 255],
    ];
}

function invoice_pdf_logo_path(): string
{
    $config = app_config();
    $invoiceLogo = trim((string)($config['invoice_logo_path'] ?? ''));
    if ($invoiceLogo !== '' && is_file($invoiceLogo)) {
        return $invoiceLogo;
    }

    $logo = trim((string)($config['logo_path'] ?? ''));

    return $logo !== '' && is_file($logo) ? $logo : '';
}

function invoice_payment_plan_amount_headers(): array
{
    return [
        ['Betrag', '(Netto)'],
        ['Betrag', '(Brutto)'],
    ];
}

function invoice_pdf_company_footer(): array
{
    return [
        'col1' => "Karvi Solutions\nGroße Gallusstraße 14\n60311 Frankfurt am Main",
        'col2' => "0711 252417 70\ninfo@karvisolutions.de",
        'col3' => "Inh.: Sharma Kartik\nAmtsgericht Frankfurt\nHRB 143175",
        'col4' => "USt-IdNr.: DE443371392\nHypoVereinsbank\nIBAN: DE49 7002 0270 0669 3643 50\nBIC: HYVE DE MM XXX",
    ];
}

function invoice_pdf_offer_number(array $contract): string
{
    $stored = trim((string)($contract['offer_number'] ?? ''));
    if ($stored !== '') {
        return $stored;
    }

    $date = trim((string)($contract['contract_date'] ?? ''));
    $timestamp = $date !== '' ? strtotime($date) : false;
    $datePart = $timestamp !== false ? date('Y-m-d', $timestamp) : date('Y-m-d');
    $id = (int)($contract['id'] ?? 0);

    return $datePart . '-' . (string)max(1, $id);
}

function invoice_pdf_valid_until_date(array $contract): string
{
    $base = trim((string)($contract['contract_date'] ?? ''));
    $timestamp = $base !== '' ? strtotime($base . ' +10 days') : strtotime('+10 days');

    return invoice_pdf_format_date(date('Y-m-d', $timestamp !== false ? $timestamp : time()));
}

function invoice_pdf_delivery_date(array $contract): string
{
    $stored = trim((string)($contract['delivery_date'] ?? ''));
    if ($stored !== '') {
        return invoice_pdf_format_date($stored);
    }

    $base = trim((string)($contract['contract_date'] ?? ''));
    $timestamp = $base !== '' ? strtotime($base . ' +25 days') : strtotime('+25 days');

    return invoice_pdf_format_date(date('Y-m-d', $timestamp !== false ? $timestamp : time()));
}

function invoice_pdf_format_date(?string $date): string
{
    if (!$date) {
        return '';
    }

    $timestamp = strtotime($date);

    return $timestamp !== false ? date('d.m.Y', $timestamp) : $date;
}

function invoice_pdf_format_money_plain(float $amount): string
{
    return number_format($amount, 2, ',', '.');
}

function invoice_pdf_intro_text(array $contract): string
{
    $line = trim((string)($contract['contract_line'] ?? ''));

    return match ($line) {
        'Karvi Website' => 'Wir bedanken uns für Ihre Anfrage. Gerne unterbreiten wir Ihnen hiermit folgendes Angebot:',
        'TSE Lieferando' => 'Wir bedanken uns für Ihre Anfrage. Gerne unterbreiten wir Ihnen hiermit folgendes Angebot für die TSE Lieferando Integration:',
        default => 'Wir bedanken uns für Ihre Anfrage. Gerne unterbreiten wir Ihnen hiermit folgendes Angebot für das Karvi POS System:',
    };
}

function invoice_pdf_fixed_price_notice(): string
{
    return 'Dieses Angebot umfasst die hier beschriebenen Leistungen zum angegebenen Festpreis. Sollten Sie im Laufe '
        . 'des Projekts Änderungen an unseren Leistungen wünschen, können zusätzliche Kosten anfallen. In diesem '
        . 'Fall informieren wir Sie im Voraus und erstellen Ihnen auf Wunsch einen Lösungsvorschlag mit '
        . 'Kostenvoranschlag.';
}

function invoice_pdf_delivery_product_label(array $contract): string
{
    $line = trim((string)($contract['contract_line'] ?? ''));

    return match ($line) {
        'Karvi Website' => 'Karvi Website Projekt',
        'TSE Lieferando' => 'Online TSE + All In One Order',
        default => 'Karvi POS System',
    };
}

function invoice_pdf_delivery_clause(array $contract): string
{
    $product = invoice_pdf_delivery_product_label($contract);
    $date = invoice_pdf_delivery_date($contract);

    return 'Der Liefertermin für das ' . $product . ' ist der ' . $date . '.';
}

function invoice_pdf_maintenance_section(array $contract): array
{
    $line = trim((string)($contract['contract_line'] ?? ''));

    if ($line === 'Karvi Website') {
        return [
            'title' => 'Pos. 2 – Jährliche Wartung & Support (exkl. USt)',
            'rows' => [
                ['pos' => 1, 'description' => 'Support-Pauschale (bis 10 Stunden)', 'quantity' => 1, 'unit_price_net' => 499.0],
                ['pos' => 2, 'description' => 'Hosting & Systemwartung Website / Apps', 'quantity' => 1, 'unit_price_net' => 120.0],
            ],
        ];
    }

    return [
        'title' => 'Pos. 2 – Jährliche Wartung inkl. iPad (exkl. USt)',
        'rows' => [
            ['pos' => 1, 'description' => 'Support-Pauschale (bis 10 Stunden)', 'quantity' => 1, 'unit_price_net' => 499.0],
            ['pos' => 2, 'description' => 'Wartung POS System inkl. Updates', 'quantity' => 1, 'unit_price_net' => 120.0],
        ],
    ];
}

function invoice_installment_info(array $contract, array $totals): array
{
    $months = max(1, (int)($contract['installment_months'] ?? 12));
    $total = (float)($totals['total'] ?? 0);

    return [
        'months' => $months,
        'monthly_total' => round($total / $months, 2),
        'total' => $total,
    ];
}

function invoice_installment_schedule(array $contract, array $totals): array
{
    return invoice_payment_plan_pos1_schedule($contract, $totals);
}

function invoice_installment_ordinal_label(int $index): string
{
    return match ($index) {
        3 => 'Dritter',
        4 => 'Vierter',
        5 => 'Fünfter',
        6 => 'Sechster',
        7 => 'Siebter',
        8 => 'Achter',
        9 => 'Neunter',
        10 => 'Zehnter',
        11 => 'Elfter',
        12 => 'Zwölfter',
        default => $index . '.',
    };
}

function invoice_installment_due_label(int $index, int $total): string
{
    if ($index === 1) {
        return 'Beim Vertragsabschluss';
    }

    if ($index === $total) {
        return 'Letzte Tranche';
    }

    if ($index === 2) {
        return 'Nach Erteilung des Auftrags';
    }

    return invoice_installment_ordinal_label($index) . ' Teilbetrag';
}

function invoice_installment_due_date(array $contract, int $index): string
{
    $base = trim((string)($contract['contract_date'] ?? ''));
    $timestamp = $base !== '' ? strtotime($base) : time();
    if ($timestamp === false) {
        $timestamp = time();
    }

    $offsetMonths = max(0, $index - 1);
    $dueTimestamp = strtotime('+' . $offsetMonths . ' months', $timestamp);

    return date('d.m.Y', $dueTimestamp !== false ? $dueTimestamp : $timestamp);
}

function invoice_payment_plan_pos1_title(array $contract): string
{
    $line = trim((string)($contract['contract_line'] ?? ''));

    $name = match ($line) {
        'Karvi Website' => 'Online Bestellsystem',
        'Karvi POS' => 'Online KassenSystem',
        'TSE Lieferando' => 'Online KassenSystem',
        default => 'Online KassenSystem',
    };

    return 'Pos. 1 – ' . $name . ' inkl. USt';
}

function invoice_payment_plan_pos2_title(): string
{
    return 'Pos. 2 – Jährliche Wartung inkl. USt';
}

function invoice_pdf_payment_plan_intro(array $contract, array $totals): string
{
    $months = max(1, (int)($contract['installment_months'] ?? 12));

    return 'Die Zahlung des Rechnungsbetrages erfolgt gemäß folgendem Zahlungsplan in '
        . $months . ' Teilbeträgen.';
}

function invoice_payment_plan_pos1_schedule(array $contract, array $totals): array
{
    $months = max(1, (int)($contract['installment_months'] ?? 12));
    $netTotal = (float)($totals['net'] ?? 0);
    $grossTotal = (float)($totals['total'] ?? 0);
    $netEach = round($netTotal / $months, 2);
    $grossEach = round($grossTotal / $months, 2);
    $schedule = [];

    for ($i = 1; $i <= $months; $i++) {
        $schedule[] = [
            'number' => $i,
            'due_label' => invoice_installment_due_label($i, $months),
            'due_date' => invoice_installment_due_date($contract, $i),
            'net' => $i === $months ? round($netTotal - ($netEach * ($months - 1)), 2) : $netEach,
            'gross' => $i === $months ? round($grossTotal - ($grossEach * ($months - 1)), 2) : $grossEach,
        ];
    }

    return $schedule;
}

function invoice_pdf_pos2_due_date(array $contract): string
{
    $base = trim((string)($contract['contract_date'] ?? ''));
    $timestamp = $base !== '' ? strtotime($base) : false;
    if ($timestamp === false) {
        $timestamp = time();
    }

    $nextYear = strtotime('+1 year', $timestamp);

    return invoice_pdf_format_date(date('Y-m-d', $nextYear !== false ? $nextYear : $timestamp));
}

function invoice_line_item_is_tse_monthly(array $item): bool
{
    $description = function_exists('mb_strtolower')
        ? mb_strtolower((string)($item['description'] ?? ''))
        : strtolower((string)($item['description'] ?? ''));

    return str_contains($description, 'tse') || str_contains($description, 'all-in-one');
}

function invoice_line_item_is_main_pos_product(array $item): bool
{
    $description = function_exists('mb_strtolower')
        ? mb_strtolower((string)($item['description'] ?? ''))
        : strtolower((string)($item['description'] ?? ''));

    return str_contains($description, 'kassensystem') || str_contains($description, 'karvi pro');
}

function invoice_contract_has_tse_monthly(array $contract): bool
{
    $line = trim((string)($contract['contract_line'] ?? ''));
    if ($line === 'TSE Lieferando') {
        return true;
    }

    foreach ($contract['line_items'] ?? [] as $item) {
        if (invoice_line_item_is_tse_monthly($item)) {
            return true;
        }
    }

    return false;
}

function invoice_contract_tse_monthly_net(array $contract): float
{
    foreach ($contract['line_items'] ?? [] as $item) {
        if (invoice_line_item_is_tse_monthly($item)) {
            return max(0.0, (float)($item['unit_price_net'] ?? 12.0));
        }
    }

    return 12.0;
}

function invoice_is_tse_only_contract(array $contract): bool
{
    $line = trim((string)($contract['contract_line'] ?? ''));
    $posType = trim((string)($contract['pos_contract_type'] ?? ''));

    if ($line === 'TSE Lieferando' || $posType === 'tse_lieferando') {
        return true;
    }

    if ((string)($contract['invoice_mode'] ?? '') !== 'pos') {
        return false;
    }

    $items = is_array($contract['line_items'] ?? null) ? $contract['line_items'] : [];
    if ($items === []) {
        return false;
    }

    $hasTseItem = false;
    $hasMainPosProduct = false;

    foreach ($items as $item) {
        if (invoice_line_item_is_tse_monthly($item)) {
            $hasTseItem = true;
            continue;
        }

        if (invoice_line_item_is_main_pos_product($item)) {
            $hasMainPosProduct = true;
        }
    }

    return $hasTseItem && !$hasMainPosProduct;
}

function invoice_should_show_payment_plan_pos2(array $contract): bool
{
    if (invoice_is_tse_only_contract($contract)) {
        return false;
    }

    return invoice_should_show_yearly_maintenance($contract);
}

function invoice_should_show_payment_plan_pos3(array $contract): bool
{
    if (invoice_is_tse_only_contract($contract)) {
        return false;
    }

    return invoice_contract_has_tse_monthly($contract);
}

function invoice_should_show_yearly_maintenance(array $contract): bool
{
    $mode = (string)($contract['invoice_mode'] ?? '');
    $line = trim((string)($contract['contract_line'] ?? ''));

    if ($line === 'TSE Lieferando') {
        return false;
    }

    return in_array($mode, ['website', 'pos'], true);
}

function invoice_payment_plan_tse_title(): string
{
    return 'Pos. 3 – TSE Monatliche Gebühren inkl. USt';
}

function invoice_tse_monthly_plan_rows(array $contract): array
{
    if (!invoice_contract_has_tse_monthly($contract)) {
        return [];
    }

    $net = invoice_contract_tse_monthly_net($contract);
    $gross = round($net * 1.19, 2);

    return [[
        'due' => 'Monatlich',
        'net' => invoice_pdf_format_money_plain($net),
        'gross' => $gross,
    ]];
}

function invoice_maintenance_plan_config(array $contract): array
{
    $mode = (string)($contract['invoice_mode'] ?? '');

    if ($mode === 'website') {
        return [
            'net' => 150.0,
            'gross' => 178.5,
        ];
    }

    return [
        'net' => 175.0,
        'gross' => 208.25,
    ];
}

function invoice_maintenance_plan_rows(array $contract): array
{
    $config = invoice_maintenance_plan_config($contract);

    return [[
        'due' => 'Jährlich zum ' . invoice_pdf_pos2_due_date($contract),
        'net' => invoice_pdf_format_money_plain($config['net']),
        'gross' => $config['gross'],
    ]];
}

function invoice_customer_detail_lines(array $contract): array
{
    $lines = preg_split('/\R+/', trim((string)($contract['customer_details'] ?? ''))) ?: [];
    $normalized = [];

    foreach ($lines as $line) {
        $line = trim((string)$line);
        if ($line !== '') {
            $normalized[] = $line;
        }
    }

    return $normalized;
}

function invoice_pdf_installment_clause(array $contract, array $totals): string
{
    $info = invoice_installment_info($contract, $totals);
    $months = (int)$info['months'];
    $monthly = invoice_pdf_format_money_plain((float)$info['monthly_total']);
    $total = invoice_pdf_format_money_plain((float)$info['total']);

    return 'Der Rechnungsbetrag von ' . $total . ' € wird in ' . $months . ' gleichen Monatsraten à '
        . $monthly . ' € (inkl. 19 % USt.) gezahlt.';
}

function invoice_document_terms_sections(array $contract): array
{
    $sections = [];

    if (invoice_should_show_yearly_maintenance($contract)) {
        $sections[] = [
            'heading' => '1.2 Leistungen für jährliche Wartung',
            'intro' => 'Die jährliche Wartung beinhaltet folgende Leistungen:',
            'items' => [
                [
                    'title' => 'Regelmäßige Datensicherung',
                    'text' => 'Alle 15 Tage werden alle Dateien gesichert.',
                ],
                [
                    'title' => 'Reaktion bei möglicherweise auftretenden Problemen',
                    'text' => 'Sollte bei der Wartung der im Angebot genannten Domain ein Problem auftreten, das zu einer Funktionsstörung dieser führt, verpflichtet sich der Dienstleister, die volle Funktionalität der Webseite(n) schnellstmöglich wiederherzustellen.',
                ],
                [
                    'title' => 'Berichtswesen',
                    'text' => 'Erstellung monatlicher Bestell- und Nutzungsstatistiken.',
                ],
            ],
        ];
    }

    $sections[] = [
        'heading' => '1.3 Liefertermin',
        'body' => invoice_pdf_delivery_clause($contract),
    ];

    if (invoice_should_show_yearly_maintenance($contract)) {
        $sections[] = [
            'heading' => '1.5 Laufzeit & Kündigung jährliche Wartung',
            'body' => "Dieser Vertrag kann nur aus wichtigem Grund (§ 314 Abs. 1 BGB) in Textform (§ 126b BGB) gekündigt werden.\n"
                . 'Der Vertrag wird auf unbestimmte Zeit geschlossen und kann von beiden Vertragsparteien durch Erklärung in Textform (§ 126b BGB) mit einer Frist von 1 Monat gekündigt werden.',
        ];
    } elseif (invoice_contract_has_tse_monthly($contract)) {
        $sections[] = [
            'heading' => '1.5 Laufzeit & Kündigung monatliche Gebühren',
            'body' => 'Die monatlichen TSE-Gebühren werden laufend monatlich abgerechnet und können von beiden Vertragsparteien mit einer Frist von 1 Monat zum Monatsende gekündigt werden.',
        ];
    }

    $sections[] = [
        'heading' => '1.6 Abgrenzungen',
        'body' => 'Karvi GmbH trägt keine Verantwortung für die Qualität oder Lieferung der Bestellungen. Diese trägt der Restaurant- oder Lieferdienstbetreiber vollumfänglich. Karvi GmbH trägt keine Verantwortung für die eingehenden Zahlungen über das Online-Bestellsystem. Die angebundenen Zahlungsanbieter gehören ausschließlich dem Kunden.',
    ];

    return $sections;
}

function invoice_pdf_terms_sections(): array
{
    return invoice_document_terms_sections([]);
}

function invoice_pdf_closing_lines(): array
{
    return [
        'Wir freuen uns, wenn unser Angebot Ihre Zustimmung findet.',
        'Bei Fragen erreichen Sie uns telefonisch — wir sind gerne für Sie da.',
        'Mit freundlichen Grüßen',
    ];
}

function invoice_document_totals_rows(array $totals): array
{
    $rows = [
        ['label' => 'Summe Netto', 'amount' => (float)($totals['subtotal'] ?? 0)],
    ];

    $discount = (float)($totals['discount'] ?? 0);
    if ($discount > 0) {
        $rows[] = ['label' => 'Special Rabatt', 'amount' => $discount, 'discount' => true];
    }

    $rows[] = ['label' => 'Gesamtsumme', 'amount' => (float)($totals['net'] ?? 0), 'net_total' => true];
    $rows[] = ['label' => 'Umsatzsteuer 19,00 %', 'amount' => (float)($totals['vat'] ?? 0), 'rule_before' => true];
    $rows[] = ['label' => 'Rechnungsbetrag', 'amount' => (float)($totals['total'] ?? 0), 'rule_after' => true];

    return $rows;
}

function invoice_format_totals_display_amount(array $row): string
{
    $amount = (float)($row['amount'] ?? 0);
    $formatted = invoice_format_money($amount);

    if (!empty($row['discount']) && $amount > 0) {
        return '- ' . $formatted;
    }

    return $formatted;
}

function invoice_pdf_line_item_unit_net(array $item): float
{
    $value = $item['unit_price_net'] ?? 0;

    if (is_int($value) || is_float($value)) {
        return (float)$value;
    }

    return invoice_parse_money($value);
}

function invoice_pdf_line_item_total_net(array $item): float
{
    if (isset($item['total_net']) && is_numeric($item['total_net'])) {
        return (float)$item['total_net'];
    }

    $qty = max(1, (int)($item['quantity'] ?? 1));

    return round($qty * invoice_pdf_line_item_unit_net($item), 2);
}
