<?php
/**
 * Krempl PostgreSQL Database Connection Class
 *
 * Usage:
 *   require_once __DIR__ . '/core/postgres/KremplDB.php';
 *   $db = new KremplDB();
 *   $results = $db->searchGeraete('AWB 921 PH');
 */

class KremplDB {
    private $pg_conn = null;
    private $mysql_conn = null;
    private $config = null;

    public function __construct($connect_mysql = false) {
        $config_file = __DIR__ . '/config.ini';

        if (!file_exists($config_file)) {
            throw new Exception("Config file not found: $config_file");
        }

        $this->config = parse_ini_file($config_file, true);

        if (!isset($this->config['postgresql'])) {
            throw new Exception("PostgreSQL config section not found in config.ini");
        }

        $this->connectPostgres();

        if ($connect_mysql) {
            $this->connectMySQL();
        }
    }

    private function connectPostgres() {
        $pg = $this->config['postgresql'];

        $conn_string = sprintf(
            "host=%s port=%s dbname=%s user=%s password=%s",
            $pg['host'] ?? 'localhost',
            $pg['port'] ?? '5432',
            $pg['database'] ?? 'krempl_data',
            $pg['user'] ?? 'krempl_user',
            $pg['password'] ?? ''
        );

        $this->pg_conn = @pg_connect($conn_string);

        if (!$this->pg_conn) {
            throw new Exception("PostgreSQL connection failed. Check credentials in config.ini");
        }
    }

    private function connectMySQL() {
        if (!isset($this->config['mysql'])) {
            throw new Exception("MySQL config section not found in config.ini");
        }

        $my = $this->config['mysql'];

        $this->mysql_conn = @mysqli_connect(
            $my['host'] ?? 'localhost',
            $my['user'] ?? '',
            $my['password'] ?? '',
            $my['database'] ?? ''
        );

        if (!$this->mysql_conn) {
            throw new Exception("MySQL connection failed: " . mysqli_connect_error());
        }

        mysqli_set_charset($this->mysql_conn, 'utf8mb4');
    }

    public function getPostgresConnection() {
        return $this->pg_conn;
    }

    public function getMySQLConnection() {
        return $this->mysql_conn;
    }

    /**
     * Search for devices using intelligent normalized search
     *
     * @param string $search_term The search term (e.g. "AWB 921 PH", "ZCS 2100B")
     * @param int $limit Maximum number of results (default: 20)
     * @return array Array of devices with scores and ersatzteile
     */
    public function searchGeraete($search_term, $limit = 20) {
        if (empty($search_term)) {
            return [];
        }

        $results = [];

        // Search for devices using the smart search function
        $query = "SELECT * FROM search_geraete_smart($1, $2)";
        $result = pg_query_params($this->pg_conn, $query, [$search_term, $limit]);

        if (!$result) {
            throw new Exception("Search query failed: " . pg_last_error($this->pg_conn));
        }

        while ($row = pg_fetch_assoc($result)) {
            // For each device, find matching ersatzteile
            $row['ersatzteile'] = $this->getErsatzteileForGeraet($row['geraet_id']);
            $results[] = $row;
        }

        return $results;
    }

    /**
     * Get all ersatzteile (spare parts) for a specific device
     *
     * @param int $geraet_id The device ID
     * @param int $limit Maximum number of results (default: 200)
     * @return array Array of ersatzteile with navision_id, krempl_id, etc.
     */
    public function getErsatzteileForGeraet($geraet_id, $limit = 200) {
        $query = "
            SELECT
                e.id AS krempl_id,
                e.navision_id,
                e.originalnummer,
                e.marke
            FROM ersatzteil_mapping em
            INNER JOIN ersatzteile e ON em.ersatzteil_id = e.id
            WHERE $1 = ANY(em.geraet_ids)
            ORDER BY e.navision_id
            LIMIT $2
        ";

        $result = pg_query_params($this->pg_conn, $query, [$geraet_id, $limit]);

        if (!$result) {
            throw new Exception("Ersatzteile query failed: " . pg_last_error($this->pg_conn));
        }

        $ersatzteile = [];
        while ($row = pg_fetch_assoc($result)) {
            $ersatzteile[] = $row;
        }

        return $ersatzteile;
    }

    /**
     * Get all devices compatible with a specific ersatzteil (by navision_id)
     *
     * @param int $navision_id The Navision ID from the shop
     * @param int $limit Maximum number of results (default: 500)
     * @return array Array of compatible devices
     */
    public function getGeraeteForNavisionId($navision_id, $limit = 500) {
        // First find the krempl ersatzteil_id
        $query1 = "SELECT id FROM ersatzteile WHERE navision_id = $1 LIMIT 1";
        $result1 = pg_query_params($this->pg_conn, $query1, [$navision_id]);

        if (!$result1) {
            throw new Exception("Navision lookup failed: " . pg_last_error($this->pg_conn));
        }

        $row = pg_fetch_assoc($result1);
        if (!$row) {
            return []; // No krempl data for this navision_id
        }

        $ersatzteil_id = $row['id'];

        // Get the array of device IDs
        $query2 = "SELECT geraet_ids FROM ersatzteil_mapping WHERE ersatzteil_id = $1";
        $result2 = pg_query_params($this->pg_conn, $query2, [$ersatzteil_id]);

        if (!$result2) {
            throw new Exception("Mapping lookup failed: " . pg_last_error($this->pg_conn));
        }

        $row = pg_fetch_assoc($result2);
        if (!$row || !$row['geraet_ids']) {
            return [];
        }

        // Parse the PostgreSQL array format
        $geraet_ids_str = trim($row['geraet_ids'], '{}');
        $geraet_ids = array_map('intval', explode(',', $geraet_ids_str));

        // Get device details
        $query3 = "
            SELECT
                id,
                nr,
                modell_bezeichnung,
                typ,
                typ_de,
                marke,
                zusatz
            FROM geraete
            WHERE id = ANY($1)
            ORDER BY marke, modell_bezeichnung
            LIMIT $2
        ";

        $result3 = pg_query_params($this->pg_conn, $query3, ['{' . implode(',', $geraet_ids) . '}', $limit]);

        if (!$result3) {
            throw new Exception("Geraete lookup failed: " . pg_last_error($this->pg_conn));
        }

        $geraete = [];
        while ($row = pg_fetch_assoc($result3)) {
            $geraete[] = $row;
        }

        return $geraete;
    }

    /**
     * Rebuild the search index after CSV re-import
     * Call this after running import.py
     *
     * @return int Number of rows indexed
     */
    public function rebuildSearchIndex() {
        $query = "SELECT rebuild_geraete_search_index()";
        $result = pg_query($this->pg_conn, $query);

        if (!$result) {
            throw new Exception("Rebuild index failed: " . pg_last_error($this->pg_conn));
        }

        $row = pg_fetch_row($result);
        return (int)$row[0];
    }

    /**
     * Get database statistics
     *
     * @return array Statistics about the database
     */
    public function getStats() {
        $stats = [];

        $queries = [
            'geraete_count' => "SELECT COUNT(*) FROM geraete",
            'ersatzteile_count' => "SELECT COUNT(*) FROM ersatzteile",
            'mapping_count' => "SELECT COUNT(*) FROM ersatzteil_mapping",
            'passendwie_count' => "SELECT COUNT(*) FROM passendwie",
            'search_index_count' => "SELECT COUNT(*) FROM geraete_search_index",
        ];

        foreach ($queries as $key => $query) {
            $result = pg_query($this->pg_conn, $query);
            if ($result) {
                $row = pg_fetch_row($result);
                $stats[$key] = (int)$row[0];
            }
        }

        return $stats;
    }

    /**
     * Get available shop items for a device (Hybrid: PostgreSQL + MySQL)
     *
     * This function combines Krempl data (PostgreSQL) with shop inventory (MySQL)
     * to show only the spare parts that are actually available in the shop.
     *
     * @param int $geraet_id The Krempl device ID
     * @param int $limit Maximum number of items to return (default: 200)
     * @return array Array of shop items with full details
     */
    public function getAvailableItemsForGeraet($geraet_id, $limit = 200) {
        // Ensure MySQL is connected
        if (!$this->mysql_conn) {
            $this->connectMySQL();
        }

        // Step 1: Get all Navision IDs from PostgreSQL for this device
        $navision_ids = [];
        $query = "
            SELECT e.navision_id
            FROM ersatzteil_mapping em
            INNER JOIN ersatzteile e ON em.ersatzteil_id = e.id
            WHERE $1 = ANY(em.geraet_ids)
              AND e.navision_id IS NOT NULL
            ORDER BY e.navision_id
        ";

        $result = pg_query_params($this->pg_conn, $query, [$geraet_id]);

        if (!$result) {
            throw new Exception("Failed to get navision_ids: " . pg_last_error($this->pg_conn));
        }

        while ($row = pg_fetch_assoc($result)) {
            $navision_ids[] = (int)$row['navision_id'];
        }

        if (empty($navision_ids)) {
            return []; // No parts found
        }

        // Step 2: Query MySQL for items that match these Navision IDs
        // Logic: number >= 8 digits → navision_id is in `number`
        //        number < 8 digits → navision_id is in `attribute_7`

        $navision_ids_str = implode(',', $navision_ids);

        $mysql_query = "
            SELECT
                i.id,
                i.number,
                i.name,
                i.attribute_7 AS navision_id_alt,
                i.inventory,
                i.base_price,
                i.manufacturer_id,
                i.structure_id,
                CASE
                    WHEN LENGTH(i.number) >= 8 THEN i.number
                    ELSE i.attribute_7
                END AS matched_navision_id
            FROM items i
            WHERE (
                (LENGTH(i.number) >= 8 AND i.number IN ($navision_ids_str))
                OR
                (LENGTH(i.number) < 8 AND i.attribute_7 IN ($navision_ids_str))
            )
            AND i.active = 1
            ORDER BY i.name
            LIMIT $limit
        ";

        $mysql_result = mysqli_query($this->mysql_conn, $mysql_query);

        if (!$mysql_result) {
            throw new Exception("MySQL query failed: " . mysqli_error($this->mysql_conn));
        }

        $items = [];
        while ($row = mysqli_fetch_assoc($mysql_result)) {
            $items[] = $row;
        }

        return $items;
    }

    public function __destruct() {
        if ($this->pg_conn) {
            pg_close($this->pg_conn);
        }
        if ($this->mysql_conn) {
            mysqli_close($this->mysql_conn);
        }
    }
}
