<?php

namespace objects;

use classes\db;
use classes\object_property;
use traits\db_object_t;

class economic_module_orders extends db
{
    use db_object_t;

    public object_property $economic_invoice_draft_id;
    public object_property $economic_invoice_id;

    public function structure(): void
    {
        $this->setTable('economic_module_orders');
    }

    public function objectChanged(): void
    {
        // Since the economic_module_orders object is not cached, there is no need to invalidate the cache
    }

    public function getByOrderId(int $orderId): economic_module_orders
    {
        global $db;
        // Create a new record in the database, if it does not exist
        $sql = "SELECT * FROM $this->table WHERE id = $orderId";
        $result = $db->query($sql);
        if ($result->num_rows > 0) {
            $this->id = $orderId;
            $this->getObjectProperties();
        } else {
            $this->add($orderId);
        }
        return $this;
    }

    /**
     * Ensure rows exist for the provided order IDs using one batched INSERT IGNORE.
     *
     * @param int[] $orderIds
     */
    public function ensureRowsForOrderIds(array $orderIds): void
    {
        $orderIds = $this->normalizeOrderIds($orderIds);
        if (empty($orderIds)) {
            return;
        }

        $this->performEnsureRowsInsert($orderIds);
    }

    /**
     * Get economic module payload for many orders as an id-keyed map.
     *
     * @param int[] $orderIds
     * @return array<int, array{id:int, invoice_draft_id:int|null, invoice_id:int|null}>
     */
    public function getByOrderIdsAsArray(array $orderIds): array
    {
        $orderIds = $this->normalizeOrderIds($orderIds);
        if (empty($orderIds)) {
            return [];
        }

        $rows = $this->fetchRowsByOrderIds($orderIds);
        $byId = [];
        foreach ($rows as $row) {
            $id = (int)($row['id'] ?? 0);
            if ($id <= 0) {
                continue;
            }
            $byId[$id] = [
                'id' => $id,
                'invoice_draft_id' => isset($row['invoice_draft_id']) && $row['invoice_draft_id'] !== null ? (int)$row['invoice_draft_id'] : null,
                'invoice_id' => isset($row['invoice_id']) && $row['invoice_id'] !== null ? (int)$row['invoice_id'] : null,
            ];
        }

        foreach ($orderIds as $orderId) {
            if (!isset($byId[$orderId])) {
                $byId[$orderId] = [
                    'id' => $orderId,
                    'invoice_draft_id' => null,
                    'invoice_id' => null,
                ];
            }
        }

        return $byId;
    }

    public function getObjectProperties(): void
    {
        $this->economic_invoice_draft_id = new object_property($this->table, $this->id, 'invoice_draft_id', 'int', true);
        $this->economic_invoice_id = new object_property($this->table, $this->id, 'invoice_id', 'int', true);
    }

    public function add(int $orderId): void
    {
        global $db, $response;
        try {
            // Create a new record in the database
            $sql = "INSERT INTO $this->table (id) VALUES ($orderId)";
            $db->query($sql);

            // Get the id of the new record
            $this->id = $orderId;

            // Set the values of the object properties
            $this->getObjectProperties();
        } catch (\Exception $e) {
            $response->error($e->getMessage());
        }
    }

    public function unlinkAllOrdersFromDraft(int $draftId): void
    {
        global $db;
        $sql = "UPDATE $this->table SET invoice_draft_id = NULL WHERE invoice_draft_id = $draftId";
        $db->query($sql);
    }

    public function asArray(): array
    {
        return [
            'id' => $this->id,
            'invoice_draft_id' => $this->economic_invoice_draft_id->value(),
            'invoice_id' => $this->economic_invoice_id->value(),
        ];
    }

    public function getUserFromDraftId(int $id): users_o|null
    {
        global $db;
        $sql = "SELECT id FROM $this->table WHERE invoice_draft_id = $id";
        $result = $db->query($sql);
        if ($result->num_rows > 0) {
            $row = $result->fetch_assoc();
            $orderId = $row['id'];
            $order = new orders_o();
            return $order->getOrderCustomer($orderId);
        }
        return null;
    }

    /**
     * @param int[] $orderIds
     * @return int[]
     */
    protected function normalizeOrderIds(array $orderIds): array
    {
        $orderIds = array_values(array_unique(array_filter(array_map('intval', $orderIds), static fn(int $id): bool => $id > 0)));
        sort($orderIds);
        return $orderIds;
    }

    /**
     * @param int[] $orderIds
     */
    protected function performEnsureRowsInsert(array $orderIds): void
    {
        global $db;
        $values = implode(',', array_map(static fn(int $id): string => "($id)", $orderIds));
        $sql = "INSERT IGNORE INTO $this->table (id) VALUES $values";
        $db->query($sql);
    }

    /**
     * @param int[] $orderIds
     * @return array<int, array<string, mixed>>
     */
    protected function fetchRowsByOrderIds(array $orderIds): array
    {
        return $this->getFieldsWhereIn(
            ['id' => $orderIds],
            ['id', 'invoice_draft_id', 'invoice_id']
        );
    }
}
