<?php
/**
 * TaxRate — Tax rate data access.
 *
 * Each rate row ties a tax class + zone together with a percentage rate.
 *
 * Fields:
 *   id             — PK
 *   class_id       — FK → tc_tax_classes
 *   zone_id        — FK → tc_tax_zones
 *   rate           — DECIMAL(8,4), e.g. 0.2000 = 20%
 *   is_compound    — applied on top of already-taxed total (1) or on the raw subtotal (0)
 *   priority       — rates with the same priority are summed; lower priority fires first
 *   includes_tax   — product price is already inclusive of tax (1) or exclusive (0)
 *
 * @package TitanCart\Modules\Tax
 */

namespace TitanCart\Modules\Tax;

use TitanCart\DB\Database;

defined( 'ABSPATH' ) || exit;

class TaxRate {

    private Database $db;

    public function __construct() {
        $this->db = titancart_db();
    }

    // ══════════════════════════════════════════════════════════════════════════
    // READ
    // ══════════════════════════════════════════════════════════════════════════

    /**
     * Return all rates for a given tax class, in the given zones.
     * Sorted by priority ASC so they are applied in the correct order.
     *
     * @param  int   $class_id
     * @param  int[] $zone_ids  IDs of matching tax zones (most-specific first).
     * @return array[]
     */
    public function get_for_class_in_zones( int $class_id, array $zone_ids ): array {
        if ( empty( $zone_ids ) ) {
            return [];
        }

        return $this->db->getArray(
            "SELECT r.*
             FROM {$this->db->table('tax_rates')} r
             WHERE r.class_id = ?i
               AND r.zone_id  IN (?a)
             ORDER BY r.priority ASC, r.id ASC",
            $class_id,
            $zone_ids
        );
    }

    /**
     * Batch-load rates for multiple class IDs in the given zones.
     * Returns: class_id → rate[]
     *
     * @param  int[] $class_ids
     * @param  int[] $zone_ids
     * @return array<int, array[]>
     */
    public function get_batch_for_classes_in_zones( array $class_ids, array $zone_ids ): array {
        if ( empty( $class_ids ) || empty( $zone_ids ) ) {
            return [];
        }

        $rows = $this->db->getArray(
            "SELECT r.*
             FROM {$this->db->table('tax_rates')} r
             WHERE r.class_id IN (?a)
               AND r.zone_id  IN (?a)
             ORDER BY r.class_id ASC, r.priority ASC, r.id ASC",
            $class_ids,
            $zone_ids
        );

        $map = [];
        foreach ( $rows as $row ) {
            $map[ (int) $row['class_id'] ][] = $row;
        }

        return $map;
    }

    /**
     * Return all rate rows for admin display.
     *
     * @param  int|null $class_id  Optional filter by class.
     * @param  int|null $zone_id   Optional filter by zone.
     * @return array[]
     */
    public function get_all( ?int $class_id = null, ?int $zone_id = null ): array {
        $conditions = [];
        $args       = [];

        if ( $class_id !== null ) {
            $conditions[] = "r.class_id = ?i";
            $args[]       = $class_id;
        }
        if ( $zone_id !== null ) {
            $conditions[] = "r.zone_id = ?i";
            $args[]       = $zone_id;
        }

        $where = $conditions ? 'WHERE ' . implode( ' AND ', $conditions ) : '';

        return $this->db->getArray(
            "SELECT r.*,
                    c.handle AS class_handle,
                    z.name   AS zone_name
             FROM {$this->db->table('tax_rates')} r
             LEFT JOIN {$this->db->table('tax_classes')} c ON c.id = r.class_id
             LEFT JOIN {$this->db->table('tax_zones')}   z ON z.id = r.zone_id
             {$where}
             ORDER BY r.class_id ASC, r.priority ASC",
            ...$args
        );
    }

    /**
     * Return a single rate by ID.
     *
     * @param  int $id
     * @return array|null
     */
    public function get_by_id( int $id ): ?array {
        return $this->db->getRow(
            "SELECT * FROM {$this->db->table('tax_rates')} WHERE id = ?i LIMIT 1",
            $id
        );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // WRITE
    // ══════════════════════════════════════════════════════════════════════════

    /**
     * Create a tax rate.
     *
     * @param  array $data {class_id, zone_id, rate, is_compound?, priority?, includes_tax?}
     * @return int  New rate ID.
     */
    public function create( array $data ): int {
        $this->db->query(
            "INSERT INTO {$this->db->table('tax_rates')}
             (class_id, zone_id, rate, is_compound, priority, includes_tax)
             VALUES (?i, ?i, ?s, ?i, ?i, ?i)",
            (int)   $data['class_id'],
            (int)   $data['zone_id'],
            number_format( (float) ( $data['rate'] ?? 0 ), 4, '.', '' ),
            (int)   ( $data['is_compound']  ?? 0 ),
            (int)   ( $data['priority']     ?? 1 ),
            (int)   ( $data['includes_tax'] ?? 0 )
        );

        return $this->db->lastInsertId();
    }

    /**
     * Update a tax rate row.
     *
     * @param  int   $id
     * @param  array $data
     * @return bool
     */
    public function update( int $id, array $data ): bool {
        $allowed = [ 'class_id', 'zone_id', 'rate', 'is_compound', 'priority', 'includes_tax' ];
        $fields  = array_intersect_key( $data, array_flip( $allowed ) );

        if ( isset( $fields['rate'] ) ) {
            $fields['rate'] = number_format( (float) $fields['rate'], 4, '.', '' );
        }

        if ( empty( $fields ) ) {
            return false;
        }

        $this->db->query(
            "UPDATE {$this->db->table('tax_rates')} SET ?u WHERE id = ?i",
            $fields,
            $id
        );

        return true;
    }

    /**
     * Delete a tax rate.
     *
     * @param  int $id
     * @return bool
     */
    public function delete( int $id ): bool {
        $this->db->query(
            "DELETE FROM {$this->db->table('tax_rates')} WHERE id = ?i",
            $id
        );
        return true;
    }
}
