<?php

defined("ABSPATH") || exit();

class Chit_Batches
{
    public static function create(
        int $product_id,
        int $quantity,
        ?string $note = null,
        ?int $created_by = null
    ): array {
        global $wpdb;
        if ($created_by == null) {
            $created_by = get_current_user_id() ?: null;
        }

        $wpdb->query("START TRANSACTION");
        try {
            $inserted = $wpdb->insert(
                $wpdb->prefix . "chit_batches",
                [
                    "product_id" => $product_id,
                    "quantity" => $quantity,
                    "note" => $note,
                    "created_by" => $created_by,
                    "created_at" => current_time("mysql"),
                ],
                ["%d", "%d", "%s", "%d", "%s"],
            );
            if ($inserted === false) {
                throw new \Exception($wpdb->last_error);
            }
            $batch_id = $wpdb->insert_id;

            $table = $wpdb->prefix . "chit_codes";
            $created_at = current_time("mysql");
            $codes = [];
            $values = [];
            $placeholders = [];
            for ($i = 0; $i < $quantity; $i++) {
                $code = Chit_Codes::generate_code();
                $codes[] = $code;
                $placeholders[] = "(%d, %d, %s, %s)";
                $values[] = $product_id;
                $values[] = $batch_id;
                $values[] = $code;
                $values[] = $created_at;
            }
            $sql =
                "INSERT INTO $table (product_id, batch_id, code, created_at) VALUES " .
                implode(",", $placeholders);
            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- $sql from $wpdb->prefix and prepare() placeholders
            $result = $wpdb->query($wpdb->prepare($sql, ...$values));
            if ($result === false) {
                throw new \Exception($wpdb->last_error);
            }
        } catch (Throwable $e) {
            $wpdb->query("ROLLBACK");
            throw $e;
        }
        $wpdb->query("COMMIT");
        return [
            "batch_id" => $batch_id,
            "note" => $note,
            "codes" => $codes,
        ];
    }

    /**
     * A batch row for an import run. Imports span products, so product_id
     * is NULL; quantity is filled in when the import finishes.
     */
    public static function create_import_batch(?string $note = null): int
    {
        global $wpdb;
        $inserted = $wpdb->insert(
            $wpdb->prefix . "chit_batches",
            [
                "product_id" => null,
                "quantity" => null,
                "source" => "import",
                "note" => $note,
                "created_by" => get_current_user_id() ?: null,
                "created_at" => current_time("mysql"),
            ],
            ["%d", "%d", "%s", "%s", "%d", "%s"],
        );
        if ($inserted === false) {
            throw new \Exception($wpdb->last_error);
        }
        return (int) $wpdb->insert_id;
    }

    public static function set_quantity(int $batch_id, int $quantity): void
    {
        global $wpdb;
        $wpdb->update(
            $wpdb->prefix . "chit_batches",
            ["quantity" => $quantity],
            ["id" => $batch_id],
            ["%d"],
            ["%d"],
        );
    }

    /**
     * Delete a batch and every code stamped with it. Returns codes deleted.
     */
    public static function delete_with_codes(int $batch_id): int
    {
        global $wpdb;
        $codes_table = $wpdb->prefix . "chit_codes";
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- $codes_table from $wpdb->prefix
        $deleted = (int) $wpdb->query(
            $wpdb->prepare("DELETE FROM $codes_table WHERE batch_id = %d", $batch_id)
        );
        $wpdb->delete(
            $wpdb->prefix . "chit_batches",
            ["id" => $batch_id],
            ["%d"],
        );
        return $deleted;
    }

    public static function get_batches(int $limit = 20, int $offset = 0): array
    {
        global $wpdb;
        $table = $wpdb->prefix . "chit_batches";
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- $table from $wpdb->prefix
        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM $table ORDER BY created_at DESC LIMIT %d OFFSET %d",
                $limit,
                $offset,
            ),
            ARRAY_A,
        );
    }
}
