403Webshell
Server IP : 193.86.120.172  /  Your IP : 216.73.216.67
Web Server : Apache/2.4.63 (Unix)
System : Linux JServices 3.10.108 #86003 SMP Wed Oct 22 13:20:46 CST 2025 x86_64
User : kubec ( 1026)
PHP Version : 8.2.28
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /volume1/web/hotel_jservices_cz/api/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /volume1/web/hotel_jservices_cz/api/rezervace.php
<?php
// ============================================================
//  Hotel DEMO — api/rezervace.php
//  CRUD rezervací, změna stavu, check-in/out časy, slevy
// ============================================================

require_once __DIR__ . '/../includes/mailer.php';

$action = $_GET['action'] ?? '';
$input  = json_decode(file_get_contents('php://input'), true) ?? [];

// Veřejné akce nevyžadují přihlášení (zákazník přes rezervační formulář)
$verejne_akce = ['vytvorit'];
$user = in_array($action, $verejne_akce) ? null : auth_check();

match ($action) {
    'seznam'          => rez_seznam($user),
    'detail'          => rez_detail($user, (int)($_GET['id'] ?? 0)),
    'vytvorit'        => rez_vytvorit($user, $input),
    'upravit'         => rez_upravit($user, (int)($_GET['id'] ?? 0), $input),
    'potvrdit'        => rez_potvrdit($user, (int)($_GET['id'] ?? 0), $input),
    'upravit-hosta'  => rez_upravit_hosta($user, (int)($_GET['id'] ?? 0), $input),
    'odebrat-doplnek' => rez_odebrat_doplnek($user, (int)($_GET['id'] ?? 0), $input),
    'zmenit-pokoj'    => rez_zmenit_pokoj($user, (int)($_GET['id'] ?? 0), $input),
    'schvalit-pokoj'  => rez_schvalit_pokoj($user, (int)($_GET['id'] ?? 0)),
    'zamitnout-pokoj' => rez_zamitnout_pokoj($user, (int)($_GET['id'] ?? 0), $input),
    'pridat-doplnek'  => rez_pridat_doplnek($user, (int)($_GET['id'] ?? 0), $input),
    'zrusit'          => rez_zrusit($user, (int)($_GET['id'] ?? 0), $input),
    'checkin-cas'     => rez_checkinout_cas($user, (int)($_GET['id'] ?? 0), 'checkin', $input),
    'checkout-cas'    => rez_checkinout_cas($user, (int)($_GET['id'] ?? 0), 'checkout', $input),
    'schvalit-cas'    => rez_schvalit_cas($user, (int)($_GET['id'] ?? 0), $input),
    'zamitnout-cas'   => rez_zamitnout_cas($user, (int)($_GET['id'] ?? 0), $input),
    'navrhnout-slevu' => rez_navrhnout_slevu($user, (int)($_GET['id'] ?? 0), $input),
    'schvalit-slevu'  => rez_rozhodnout_slevu($user, (int)($_GET['id'] ?? 0), true, $input),
    'zamitnout-slevu' => rez_rozhodnout_slevu($user, (int)($_GET['id'] ?? 0), false, $input),
    'cena-override'   => rez_cena_override($user, (int)($_GET['id'] ?? 0), $input),
    'dnes'            => rez_dnes($user),
    'today'           => rez_dnes($user),
    default           => api_response(false, null, 'Neznámá akce', 400),
};

// ------------------------------------------------------------
//  SEZNAM
// ------------------------------------------------------------
function rez_seznam(array $user): never {
    $stav      = $_GET['stav'] ?? '';
    $datum_od  = $_GET['datum_od'] ?? '';
    $datum_do  = $_GET['datum_do'] ?? '';
    $pokoj_id  = (int)($_GET['pokoj_id'] ?? 0);
    $search    = trim($_GET['search'] ?? '');
    $limit     = min((int)($_GET['limit'] ?? 50), 200);
    $offset    = (int)($_GET['offset'] ?? 0);

    $where  = ['1=1'];
    $params = [];

    if ($stav) { $where[] = 'r.stav = ?'; $params[] = $stav; }
    if ($datum_od) { $where[] = 'r.datum_prijezdu >= ?'; $params[] = $datum_od; }
    if ($datum_do) { $where[] = 'r.datum_odjezdu <= ?'; $params[] = $datum_do; }
    if ($pokoj_id) { $where[] = 'r.pokoj_id = ?'; $params[] = $pokoj_id; }
    if ($search) {
        $where[] = '(r.jmeno LIKE ? OR r.prijmeni LIKE ? OR r.email LIKE ? OR r.telefon LIKE ? OR r.id = ?)';
        $s = '%' . $search . '%';
        $id_search = ctype_digit($search) ? (int)$search : 0;
        $params = array_merge($params, [$s, $s, $s, $s, $id_search]);
    }

    $sql_where = implode(' AND ', $where);
    $celkem    = (int)db_val("SELECT COUNT(*) FROM rezervace r WHERE {$sql_where}", $params);

    $rezervace = db_rows(
        "SELECT r.id, r.pokoj_id, r.datum_prijezdu, r.datum_odjezdu, r.pocet_noci,
                r.jmeno, r.prijmeni, r.email, r.telefon, r.pocet_hostu, r.jazyk,
                r.stav, r.cena_zaklad, r.cena_upravena,
                r.sleva_castka, r.sleva_stav, r.na_firmu, r.firma,
                r.checkin_cas, r.checkout_cas, r.vytvoreno,
                r.cas_zadost_typ, r.cas_zadost_hodnota, r.cas_zadost_stav, r.cas_zadost_poznamka,
                r.pokoj_zadost_pokoj_id, r.pokoj_zadost_cena_typu, r.pokoj_zadost_stav, r.pokoj_zadost_poznamka,
                r.sleva_manazer_poznamka,
                p.cislo AS pokoj_cislo,
                COALESCE(p.nazev, CONCAT('Pokoj ', p.cislo)) AS pokoj_nazev,
                t.nazev AS typ_nazev
         FROM rezervace r
         JOIN pokoje p ON p.id = r.pokoj_id
         JOIN typy_pokoju t ON t.id = p.typ_id
         WHERE {$sql_where}
         ORDER BY r.datum_prijezdu DESC
         LIMIT {$limit} OFFSET {$offset}",
        $params
    );

    api_response(true, ['rezervace' => $rezervace, 'celkem' => $celkem,
                        'limit' => $limit, 'offset' => $offset]);
}

// ------------------------------------------------------------
//  DETAIL
// ------------------------------------------------------------
function rez_detail(array $user, int $id): never {
    if (!$id) api_response(false, null, 'Chybí ID', 400);

    $rez = db_row(
        "SELECT r.*,
                p.cislo AS pokoj_cislo,
                COALESCE(p.nazev, CONCAT('Pokoj ', p.cislo)) AS pokoj_nazev,
                p.typ_id,
                t.nazev AS typ_nazev, t.kapacita, t.cena_za_noc,
                CONCAT(u.jmeno, ' ', u.prijmeni) AS vytvoril_jmeno,
                CONCAT(ci.jmeno, ' ', ci.prijmeni) AS checkin_zmenil_jmeno,
                CONCAT(co.jmeno, ' ', co.prijmeni) AS checkout_zmenil_jmeno,
                CONCAT(sl.jmeno, ' ', sl.prijmeni) AS sleva_schvalil_jmeno
         FROM rezervace r
         JOIN pokoje p ON p.id = r.pokoj_id
         JOIN typy_pokoju t ON t.id = p.typ_id
         LEFT JOIN uzivatele u  ON u.id  = r.vytvoril_id
         LEFT JOIN uzivatele ci ON ci.id = r.checkin_zmenil_id
         LEFT JOIN uzivatele co ON co.id = r.checkout_zmenil_id
         LEFT JOIN uzivatele sl ON sl.id = r.sleva_schvalil_id
         WHERE r.id = ?",
        [$id]
    );
    if (!$rez) api_response(false, null, 'Rezervace nenalezena', 404);

    $doplnky  = db_rows('SELECT * FROM rezervace_doplnky WHERE rezervace_id = ?', [$id]);
    $hodnoceni = db_row('SELECT hvezdicky, vytvoreno FROM hodnoceni WHERE rezervace_id = ?', [$id]);

    api_response(true, ['rezervace' => $rez, 'doplnky' => $doplnky, 'hodnoceni' => $hodnoceni]);
}

// ------------------------------------------------------------
//  VYTVOŘENÍ
// ------------------------------------------------------------
function rez_vytvorit(?array $user, array $input): never {
    $data = _rez_validuj($input, $user);

    // Automatické přiřazení konkrétního pokoje dle typu
    $pokoj_id = _rez_prirad_pokoj($data['typ_id'], $data['datum_prijezdu'], $data['datum_odjezdu']);
    if (!$pokoj_id) {
        api_response(false, null, 'Vybraný typ pokoje není v tomto termínu dostupný. Zkuste jiný termín nebo typ pokoje.', 409);
    }
    $data['pokoj_id'] = $pokoj_id;

    // Cena pokoje (snapshot z typu)
    $cena_za_noc = (float)db_val('SELECT cena_za_noc FROM typy_pokoju WHERE id = ?', [$data['typ_id']]);
    $cena_zaklad = round($cena_za_noc * $data['pocet_noci'], 2);

    // Automatická sleva pro 1 hosta ve vícelůžkovém pokoji
    $sleva_castka   = null;
    $sleva_stav     = null;
    $sleva_poznamka = null;
    $sleva_jl       = 0;

    $kapacita = (int)db_val('SELECT kapacita FROM typy_pokoju WHERE id = ?', [$data['typ_id']]);
    if ($data['pocet_hostu'] === 1 && $kapacita > 1) {
        $sleva_zapnuta = nastaveni('sleva_jednoluzko_zapnuta', '1') === '1';
        $sleva_procent = (int)nastaveni('sleva_jednoluzko_procent', '20');
        if ($sleva_zapnuta && $sleva_procent > 0) {
            $sleva_castka   = round($cena_zaklad * $sleva_procent / 100, 2);
            $sleva_stav     = 'schvalena';
            $sleva_poznamka = 'Automatická sleva ' . $sleva_procent . ' % — 1 host ve vícelůžkovém pokoji';
            $sleva_jl       = 1;
        }
    }

    $token = bin2hex(random_bytes(32));

    $id = db_insert(
        'INSERT INTO rezervace
         (pokoj_id, datum_prijezdu, datum_odjezdu, pocet_noci,
          jmeno, prijmeni, email, telefon, pocet_hostu, poznamka,
          na_firmu, firma, ico, dic, faktura_ulice, faktura_psc, faktura_mesto,
          stav, cena_zaklad, sleva_castka, sleva_stav, sleva_poznamka,
          sleva_jednoluzko, token_zmena, vytvoril_id, jazyk)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
        [
            $data['pokoj_id'], $data['datum_prijezdu'], $data['datum_odjezdu'], $data['pocet_noci'],
            $data['jmeno'], $data['prijmeni'], $data['email'], $data['telefon'],
            $data['pocet_hostu'], $data['poznamka'],
            $data['na_firmu'], $data['firma'], $data['ico'], $data['dic'],
            $data['faktura_ulice'], $data['faktura_psc'], $data['faktura_mesto'],
            'ceka', $cena_zaklad, $sleva_castka, $sleva_stav, $sleva_poznamka,
            $sleva_jl, $token, $user['id'] ?? null, $data['jazyk'],
        ]
    );

    if (!empty($input['doplnky'])) {
        _rez_uloz_doplnky($id, $input['doplnky'], $data['pocet_noci'], $data['pocet_hostu']);
    }

    _rez_upsert_zakaznik($data);

    // Odeslat e-mail - chyba nesmí přerušit JSON odpověď
    ob_start();
    try {
        odeslat_potvrzeni_rezervace($id);
        error_log('[Rezervace] E-mail odeslán pro #' . $id);
    } catch (\Throwable $e) {
        error_log('[Rezervace] E-mail selhal pro #' . $id . ': ' . $e->getMessage());
    } finally {
        ob_end_clean();
    }

    api_response(true, ['id' => $id, 'token' => $token]);
}

// ------------------------------------------------------------
//  ÚPRAVA
// ------------------------------------------------------------
function rez_upravit(array $user, int $id, array $input): never {
    if (!$id) api_response(false, null, 'Chybí ID', 400);

    if ($user['role'] === 'zamestnanec' && !auth_has_opravneni($user, 'zmena_rezervace')) {
        api_response(false, null, 'Nemáte oprávnění upravovat rezervace.', 403);
    }

    $rez = db_row('SELECT * FROM rezervace WHERE id = ?', [$id]);
    if (!$rez) api_response(false, null, 'Rezervace nenalezena', 404);
    if ($rez['stav'] === 'zrusena') api_response(false, null, 'Zrušenou rezervaci nelze upravit.', 400);

    $data = _rez_validuj($input, $user);

    // Pro úpravu zachováme stávající pokoj pokud se termín nemění
    $meni_termin = $data['typ_id'] !== (int)db_val('SELECT typ_id FROM pokoje WHERE id = ?', [$rez['pokoj_id']])
                || $data['datum_prijezdu'] !== $rez['datum_prijezdu']
                || $data['datum_odjezdu']  !== $rez['datum_odjezdu'];

    if ($meni_termin) {
        $pokoj_id = _rez_prirad_pokoj($data['typ_id'], $data['datum_prijezdu'], $data['datum_odjezdu'], $id);
        if (!$pokoj_id) api_response(false, null, 'Zvolený typ pokoje není v tomto termínu dostupný.', 409);
        $data['pokoj_id'] = $pokoj_id;
    } else {
        $data['pokoj_id'] = (int)$rez['pokoj_id'];
    }

    $cena_zaklad = (float)$rez['cena_zaklad'];
    if ($meni_termin) {
        $cena_za_noc = (float)db_val('SELECT cena_za_noc FROM typy_pokoju WHERE id = ?', [$data['typ_id']]);
        $cena_zaklad = round($cena_za_noc * $data['pocet_noci'], 2);
    }

    db_query(
        'UPDATE rezervace SET
         pokoj_id=?, datum_prijezdu=?, datum_odjezdu=?, pocet_noci=?,
         jmeno=?, prijmeni=?, email=?, telefon=?, pocet_hostu=?, poznamka=?,
         na_firmu=?, firma=?, ico=?, dic=?, faktura_ulice=?, faktura_psc=?, faktura_mesto=?,
         cena_zaklad=?
         WHERE id=?',
        [
            $data['pokoj_id'], $data['datum_prijezdu'], $data['datum_odjezdu'], $data['pocet_noci'],
            $data['jmeno'], $data['prijmeni'], $data['email'], $data['telefon'],
            $data['pocet_hostu'], $data['poznamka'],
            $data['na_firmu'], $data['firma'], $data['ico'], $data['dic'],
            $data['faktura_ulice'], $data['faktura_psc'], $data['faktura_mesto'],
            $cena_zaklad, $id,
        ]
    );

    if (isset($input['doplnky'])) {
        db_query('DELETE FROM rezervace_doplnky WHERE rezervace_id = ?', [$id]);
        if (!empty($input['doplnky'])) {
            _rez_uloz_doplnky($id, $input['doplnky'], $data['pocet_noci'], $data['pocet_hostu']);
        }
    }

    if ($meni_termin) {
        try { odeslat_zmenu_terminu($id); } catch (\Exception $e) { error_log($e->getMessage()); }
    }

    api_response(true, null);
}

// ------------------------------------------------------------
//  ZRUŠENÍ
// ------------------------------------------------------------
function rez_zrusit(array $user, int $id, array $input): never {
    if (!$id) api_response(false, null, 'Chybí ID', 400);

    if ($user['role'] === 'zamestnanec' && !auth_has_opravneni($user, 'storno_rezervace')) {
        api_response(false, null, 'Nemáte oprávnění rušit rezervace.', 403);
    }

    $rez = db_row('SELECT * FROM rezervace WHERE id = ?', [$id]);
    if (!$rez) api_response(false, null, 'Rezervace nenalezena', 404);
    if ($rez['stav'] === 'zrusena') api_response(false, null, 'Rezervace je již zrušena.', 400);

    $duvod = trim($input['duvod'] ?? '');
    db_query("UPDATE rezervace SET stav='zrusena', duvod_zruseni=? WHERE id=?", [$duvod ?: null, $id]);

    // Interní storno (zaměstnanec/manažer):
    // - hotel_email (sdílená recepční schránka) se nikdy nenotifikuje — storno udělal personál
    // - manažeři s vlastní preferencí notif_storno chtějí přehled bez ohledu na to, kdo storno udělal,
    //   takže pokud storno provedl zaměstnanec, manažeři se notifikují; pokud storno provedl
    //   sám manažer/admin, notifikace ostatním manažerům jde také (nemá smysl ji blokovat).
    try {
        odeslat_storno($id, notifikovat_hotel: false, notifikovat_manazery: true);
    } catch (\Exception $e) { error_log($e->getMessage()); }

    api_response(true, null);
}

// ------------------------------------------------------------
//  ZMĚNA CHECK-IN / CHECK-OUT ČASU
// ------------------------------------------------------------
function rez_checkinout_cas(array $user, int $id, string $typ, array $input): never {
    if (!$id) api_response(false, null, 'Chybí ID', 400);

    if ($user['role'] === 'zamestnanec' && !auth_has_opravneni($user, 'zmena_terminu')) {
        api_response(false, null, 'Nemáte oprávnění měnit časy příjezdu/odjezdu.', 200);
    }

    $rez = db_row('SELECT * FROM rezervace WHERE id = ?', [$id]);
    if (!$rez) api_response(false, null, 'Rezervace nenalezena', 404);

    $cas = trim($input['cas'] ?? '');
    if (!preg_match('/^\d{2}:\d{2}$/', $cas)) {
        api_response(false, null, 'Neplatný formát času (HH:MM).', 400);
    }

    // Zaměstnanec — uložit jako žádost o schválení
    if ($user['role'] === 'zamestnanec') {
        $vychozi_checkin  = nastaveni('checkin_cas',  '14:00');
        $vychozi_checkout = nastaveni('checkout_cas', '10:00');
        $vychozi = $typ === 'checkin' ? $vychozi_checkin : $vychozi_checkout;

        // Zkontrolovat zda je čas nestandardní
        $je_nestandardni = $cas !== $vychozi;

        if ($je_nestandardni && !empty($input['zadost'])) {
            // Uložit jako žádost — čeká na schválení manažera
            db_query(
                "UPDATE rezervace SET cas_zadost_typ=?, cas_zadost_hodnota=?, cas_zadost_stav='ceka', cas_zadost_user_id=? WHERE id=?",
                [$typ, $cas, $user['id'], $id]
            );
            // Notifikovat manažera e-mailem
            try {
                require_once __DIR__ . '/../includes/mailer.php';
                odeslat_zadost_cas($id, $user, $typ, $cas);
            } catch (\Throwable $e) { error_log($e->getMessage()); }
            api_response(true, ['zadost' => true]);
        } elseif ($je_nestandardni) {
            // První volání — informovat frontend že je nestandardní
            api_response(true, ['nestandardni' => true, 'vychozi' => $vychozi]);
        }
        // Standardní čas — uložit rovnou
    }

    // Admin/manažer nebo standardní čas — uložit přímo
    $sloupec_cas    = $typ === 'checkin' ? 'checkin_cas'       : 'checkout_cas';
    $sloupec_zmenil = $typ === 'checkin' ? 'checkin_zmenil_id' : 'checkout_zmenil_id';
    db_query("UPDATE rezervace SET {$sloupec_cas}=?, {$sloupec_zmenil}=? WHERE id=?",
        [$cas, $user['id'], $id]);

    api_response(true, null);
}

// ------------------------------------------------------------
//  SCHVÁLENÍ / ZAMÍTNUTÍ ŽÁDOSTI O ZMĚNU ČASU
// ------------------------------------------------------------
function rez_schvalit_cas(array $user, int $id, array $input): never {
    if (!in_array($user['role'], ['admin','manazer'], true)) {
        api_response(false, null, 'Pouze manažer může schvalovat.', 200);
    }
    $rez = db_row("SELECT * FROM rezervace WHERE id = ? AND cas_zadost_stav = 'ceka'", [$id]);
    if (!$rez) api_response(false, null, 'Žádná čekající žádost.', 200);

    $typ = $rez['cas_zadost_typ'];
    $cas = $rez['cas_zadost_hodnota'];
    $sloupec = $typ === 'checkin' ? 'checkin_cas' : 'checkout_cas';
    $zmenil  = $typ === 'checkin' ? 'checkin_zmenil_id' : 'checkout_zmenil_id';

    db_query(
        "UPDATE rezervace SET {$sloupec}=?, {$zmenil}=?, cas_zadost_stav='schvaleno' WHERE id=?",
        [$cas, $user['id'], $id]
    );

    // E-mail zákazníkovi
    try {
        require_once __DIR__ . '/../includes/mailer.php';
        odeslat_schvaleni_cas($id, $typ, $cas);
    } catch (\Throwable $e) { error_log($e->getMessage()); }

    api_response(true, null);
}

function rez_zamitnout_cas(array $user, int $id, array $input): never {
    if (!in_array($user['role'], ['admin','manazer'], true)) {
        api_response(false, null, 'Pouze manažer může zamítat.', 200);
    }
    $rez = db_row("SELECT * FROM rezervace WHERE id = ? AND cas_zadost_stav = 'ceka'", [$id]);
    if (!$rez) api_response(false, null, 'Žádná čekající žádost.', 200);

    $poznamka = trim($input['poznamka'] ?? '');
    db_query("UPDATE rezervace SET cas_zadost_stav='zamitnuto', cas_zadost_poznamka=? WHERE id=?",
        [$poznamka ?: null, $id]);

    api_response(true, null);
}

// ------------------------------------------------------------
//  NÁVRH SLEVY
// ------------------------------------------------------------
function rez_navrhnout_slevu(array $user, int $id, array $input): never {
    if (!$id) api_response(false, null, 'Chybí ID', 400);

    $rez = db_row('SELECT * FROM rezervace WHERE id = ?', [$id]);
    if (!$rez) api_response(false, null, 'Rezervace nenalezena', 404);
    if ($rez['stav'] === 'zrusena') api_response(false, null, 'Zrušenou rezervaci nelze upravit.', 400);

    $castka   = (float)($input['castka'] ?? 0);
    $poznamka = trim($input['poznamka'] ?? '');

    if ($castka <= 0) api_response(false, null, 'Výše slevy musí být kladná.', 400);
    if (!$poznamka)   api_response(false, null, 'Uveďte důvod slevy.', 400);

    if (in_array($user['role'], ['admin', 'manazer'], true)) {
        db_query("UPDATE rezervace SET sleva_castka=?, sleva_stav='schvalena', sleva_poznamka=?, sleva_schvalil_id=? WHERE id=?",
            [$castka, $poznamka, $user['id'], $id]);
        api_response(true, ['stav' => 'schvalena']);
    }

    db_query("UPDATE rezervace SET sleva_castka=?, sleva_stav='navrzena', sleva_poznamka=? WHERE id=?",
        [$castka, $poznamka, $id]);

    try { odeslat_navrh_slevy($id, $user, $castka, $poznamka); } catch (\Exception $e) { error_log($e->getMessage()); }

    api_response(true, ['stav' => 'navrzena']);
}

// ------------------------------------------------------------
//  SCHVÁLENÍ / ZAMÍTNUTÍ SLEVY
// ------------------------------------------------------------
function rez_rozhodnout_slevu(array $user, int $id, bool $schvalit, array $input): never {
    auth_require_role($user, ['admin', 'manazer']);
    if (!$id) api_response(false, null, 'Chybí ID', 400);

    $rez = db_row("SELECT sleva_stav FROM rezervace WHERE id = ?", [$id]);
    if (!$rez) api_response(false, null, 'Rezervace nenalezena', 404);
    if ($rez['sleva_stav'] !== 'navrzena') {
        api_response(false, null, 'Sleva není ve stavu čekající na schválení.', 400);
    }

    $novy_stav = $schvalit ? 'schvalena' : 'zamitnuta';
    $poznamka  = trim($input['poznamka'] ?? '');
    db_query('UPDATE rezervace SET sleva_stav=?, sleva_schvalil_id=?, sleva_manazer_poznamka=? WHERE id=?',
        [$novy_stav, $user['id'], $poznamka ?: null, $id]);

    api_response(true, ['stav' => $novy_stav]);
}

// ------------------------------------------------------------
//  PŘÍMÝ OVERRIDE CENY
// ------------------------------------------------------------
function rez_cena_override(array $user, int $id, array $input): never {
    auth_require_role($user, ['admin', 'manazer']);
    if (!$id) api_response(false, null, 'Chybí ID', 400);

    $cena = isset($input['cena']) ? (float)$input['cena'] : null;
    if ($cena !== null && $cena < 0) api_response(false, null, 'Cena nemůže být záporná.', 400);

    db_query('UPDATE rezervace SET cena_upravena=? WHERE id=?', [$cena, $id]);
    api_response(true, null);
}

// ------------------------------------------------------------
//  DNEŠNÍ PŘÍJEZDY A ODJEZDY
// ------------------------------------------------------------
function rez_dnes(array $user): never {
    $dnes = date('Y-m-d');

    $prijezdy = db_rows(
        "SELECT r.id, r.jmeno, r.prijmeni, r.pocet_hostu,
                r.checkin_cas, r.poznamka, r.stav,
                p.cislo AS pokoj_cislo,
                COALESCE(p.nazev, CONCAT('Pokoj ', p.cislo)) AS pokoj_nazev
         FROM rezervace r JOIN pokoje p ON p.id = r.pokoj_id
         WHERE r.datum_prijezdu = ? AND r.stav != 'zrusena'
         ORDER BY COALESCE(r.checkin_cas, '14:00') ASC",
        [$dnes]
    );

    $odjezdy = db_rows(
        "SELECT r.id, r.jmeno, r.prijmeni, r.pocet_hostu,
                r.checkout_cas, r.stav,
                p.cislo AS pokoj_cislo,
                COALESCE(p.nazev, CONCAT('Pokoj ', p.cislo)) AS pokoj_nazev
         FROM rezervace r JOIN pokoje p ON p.id = r.pokoj_id
         WHERE r.datum_odjezdu = ? AND r.stav != 'zrusena'
         ORDER BY COALESCE(r.checkout_cas, '10:00') ASC",
        [$dnes]
    );

    $ubytovani = db_rows(
        "SELECT r.id, r.jmeno, r.prijmeni, r.pocet_hostu,
                r.datum_prijezdu, r.datum_odjezdu,
                p.cislo AS pokoj_cislo,
                COALESCE(p.nazev, CONCAT('Pokoj ', p.cislo)) AS pokoj_nazev
         FROM rezervace r JOIN pokoje p ON p.id = r.pokoj_id
         WHERE r.datum_prijezdu <= ? AND r.datum_odjezdu > ? AND r.stav != 'zrusena'
         ORDER BY r.datum_odjezdu ASC",
        [$dnes, $dnes]
    );

    api_response(true, ['datum' => $dnes, 'prijezdy' => $prijezdy,
                        'odjezdy' => $odjezdy, 'ubytovani' => $ubytovani]);
}

// ------------------------------------------------------------
//  INTERNÍ HELPERY
// ------------------------------------------------------------
function _rez_validuj(array $input, ?array $user): array {
    $typ_id        = (int)($input['typ_id'] ?? 0);
    $datum_od      = trim($input['datum_prijezdu'] ?? '');
    $datum_do      = trim($input['datum_odjezdu'] ?? '');
    $jmeno         = trim($input['jmeno'] ?? '');
    $prijmeni      = trim($input['prijmeni'] ?? '');
    $email         = trim($input['email'] ?? '');
    $telefon       = trim($input['telefon'] ?? '');
    $pocet_hostu   = (int)($input['pocet_hostu'] ?? 1);
    $poznamka      = trim($input['poznamka'] ?? '');
    $na_firmu      = !empty($input['na_firmu']) ? 1 : 0;
    $firma         = trim($input['firma']         ?? '');
    $ico           = trim($input['ico']           ?? '');
    $dic           = trim($input['dic']           ?? '');
    $faktura_ulice = trim($input['faktura_ulice'] ?? '');
    $faktura_psc   = trim($input['faktura_psc']   ?? '');
    $faktura_mesto = trim($input['faktura_mesto'] ?? '');
    $jazyk         = in_array($input['jazyk'] ?? '', ['cs','en','de'], true) ? $input['jazyk'] : 'cs';

    if (!$typ_id)   api_response(false, null, 'Vyberte typ pokoje.', 400);
    if (!$datum_od) api_response(false, null, 'Zadejte datum příjezdu.', 400);
    if (!$datum_do) api_response(false, null, 'Zadejte datum odjezdu.', 400);
    if (!$jmeno)    api_response(false, null, 'Zadejte jméno hosta.', 400);
    if (!$prijmeni) api_response(false, null, 'Zadejte příjmení hosta.', 400);
    if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
        api_response(false, null, 'Zadejte platný e-mail.', 400);
    }
    if (!$telefon)  api_response(false, null, 'Zadejte telefonní číslo.', 400);
    if ($datum_od >= $datum_do) {
        api_response(false, null, 'Datum odjezdu musí být po datu příjezdu.', 400);
    }
    if ($pocet_hostu < 1) api_response(false, null, 'Počet hostů musí být alespoň 1.', 400);
    if ($na_firmu && !$firma) {
        api_response(false, null, 'Při objednávce na firmu zadejte název firmy.', 400);
    }

    $typ = db_row('SELECT id, kapacita, min_pobyt_noci FROM typy_pokoju WHERE id = ? AND aktivni = 1', [$typ_id]);
    if (!$typ) api_response(false, null, 'Zvolený typ pokoje neexistuje.', 400);

    if ($pocet_hostu > (int)$typ['kapacita']) {
        api_response(false, null, 'Typ pokoje má kapacitu ' . $typ['kapacita'] . ' osob, zadali jste ' . $pocet_hostu . '.', 400);
    }

    $pocet_noci = _rez_pocet_noci($datum_od, $datum_do);

    if ($pocet_noci < (int)$typ['min_pobyt_noci']) {
        api_response(false, null, 'Minimální délka pobytu pro tento typ pokoje je ' . $typ['min_pobyt_noci'] . ' nocí.', 400);
    }

    return [
        'typ_id'         => $typ_id,
        'pokoj_id'       => 0,
        'datum_prijezdu' => $datum_od,
        'datum_odjezdu'  => $datum_do,
        'pocet_noci'     => $pocet_noci,
        'jmeno'          => $jmeno,
        'prijmeni'       => $prijmeni,
        'email'          => $email,
        'telefon'        => $telefon,
        'pocet_hostu'    => $pocet_hostu,
        'poznamka'       => $poznamka ?: null,
        'na_firmu'       => $na_firmu,
        'firma'          => $firma ?: null,
        'ico'            => $ico ?: null,
        'dic'            => $dic ?: null,
        'faktura_ulice'  => $faktura_ulice ?: null,
        'faktura_psc'    => $faktura_psc ?: null,
        'faktura_mesto'  => $faktura_mesto ?: null,
        'jazyk'          => $jazyk,
    ];
}

function _rez_prirad_pokoj(int $typ_id, string $datum_od, string $datum_do, int $exclude_id = 0): int {
    $pokoje = db_rows(
        'SELECT id FROM pokoje WHERE typ_id = ? AND aktivni = 1 ORDER BY poradi ASC, cislo ASC',
        [$typ_id]
    );
    foreach ($pokoje as $p) {
        $params = [$p['id'], $datum_do, $datum_od];
        $exclude_sql = '';
        if ($exclude_id) { $exclude_sql = 'AND id != ?'; $params[] = $exclude_id; }

        $konflikt = db_val(
            "SELECT id FROM rezervace
             WHERE pokoj_id = ? AND stav != 'zrusena'
               AND datum_prijezdu < ? AND datum_odjezdu > ?
               {$exclude_sql} LIMIT 1",
            $params
        );
        $blokovano = db_val(
            'SELECT id FROM blokovane_terminy WHERE pokoj_id = ? AND datum_od < ? AND datum_do > ? LIMIT 1',
            [$p['id'], $datum_do, $datum_od]
        );
        if (!$konflikt && !$blokovano) return (int)$p['id'];
    }
    return 0;
}

function _rez_zkontroluj_dostupnost(int $pokoj_id, string $datum_od, string $datum_do, int $exclude_id = 0): void {
    $params = [$datum_do, $datum_od, $pokoj_id];
    $exclude_sql = '';
    if ($exclude_id) { $exclude_sql = 'AND r.id != ?'; $params[] = $exclude_id; }

    $konflikt = db_val(
        "SELECT r.id FROM rezervace r
         WHERE r.stav != 'zrusena'
           AND r.datum_prijezdu < ? AND r.datum_odjezdu > ?
           AND r.pokoj_id = ? {$exclude_sql} LIMIT 1",
        $params
    );
    if ($konflikt) api_response(false, null, 'Zvolený pokoj je v tomto termínu obsazen.', 409);

    $blokovano = db_val(
        'SELECT id FROM blokovane_terminy WHERE pokoj_id = ? AND datum_od < ? AND datum_do > ? LIMIT 1',
        [$pokoj_id, $datum_do, $datum_od]
    );
    if ($blokovano) api_response(false, null, 'Zvolený pokoj je v tomto termínu blokován.', 409);
}

function _rez_uloz_doplnky(int $rezervace_id, array $doplnky_ids, int $pocet_noci, int $pocet_hostu): void {
    foreach ($doplnky_ids as $doplnek_id) {
        $d = db_row('SELECT * FROM doplnky WHERE id = ? AND aktivni = 1', [(int)$doplnek_id]);
        if (!$d) continue;

        $noci_pro_vypocet  = in_array($d['typ_uctovani'], ['za_noc', 'za_osobu_noc'], true) ? $pocet_noci : 1;
        $hostu_pro_vypocet = $d['typ_uctovani'] === 'za_osobu_noc' ? $pocet_hostu : 1;
        $cena_celkem = round($d['cena'] * $noci_pro_vypocet * $hostu_pro_vypocet, 2);

        db_query(
            'INSERT INTO rezervace_doplnky (rezervace_id, doplnek_id, nazev, cena, typ_uctovani, pocet_noci, cena_celkem)
             VALUES (?, ?, ?, ?, ?, ?, ?)',
            [$rezervace_id, $d['id'], $d['nazev'], $d['cena'], $d['typ_uctovani'],
             $noci_pro_vypocet, $cena_celkem]
        );
    }

    // Sjednotit cena_upravena hned teď, aby DB odpovídala zobrazené ceně
    // (jinak by cena_upravena zůstala NULL a pozdější operace s doplňky
    //  by nesprávně počítaly "starou cenu" jen z cena_zaklad)
    $suma_doplnku = (float)db_val('SELECT COALESCE(SUM(cena_celkem),0) FROM rezervace_doplnky WHERE rezervace_id = ?', [$rezervace_id]);
    if ($suma_doplnku > 0) {
        $cena_zaklad = (float)db_val('SELECT cena_zaklad FROM rezervace WHERE id = ?', [$rezervace_id]);
        db_query('UPDATE rezervace SET cena_upravena = ? WHERE id = ?', [$cena_zaklad + $suma_doplnku, $rezervace_id]);
    }
}

function _rez_upsert_zakaznik(array $data): void {
    db_query(
        'INSERT INTO zakaznici (jmeno, prijmeni, email, telefon, firma, ico, dic, faktura_ulice, faktura_psc, faktura_mesto)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
         ON DUPLICATE KEY UPDATE
             jmeno         = VALUES(jmeno),
             prijmeni      = VALUES(prijmeni),
             telefon       = COALESCE(VALUES(telefon), telefon),
             firma         = COALESCE(VALUES(firma), firma),
             ico           = COALESCE(VALUES(ico), ico),
             dic           = COALESCE(VALUES(dic), dic),
             faktura_ulice = COALESCE(VALUES(faktura_ulice), faktura_ulice),
             faktura_psc   = COALESCE(VALUES(faktura_psc), faktura_psc),
             faktura_mesto = COALESCE(VALUES(faktura_mesto), faktura_mesto)',
        [
            $data['jmeno'], $data['prijmeni'], $data['email'], $data['telefon'],
            $data['firma'] ?? null, $data['ico'] ?? null, $data['dic'] ?? null,
            $data['faktura_ulice'] ?? null, $data['faktura_psc'] ?? null, $data['faktura_mesto'] ?? null,
        ]
    );
}

function _rez_pocet_noci(string $od, string $do): int {
    return max(1, (int)(new DateTime($od))->diff(new DateTime($do))->days);
}

// ============================================================
//  POTVRZENÍ REZERVACE
// ============================================================
function rez_potvrdit(array $user, int $id, array $input): never {
    if (!$id) api_response(false, null, 'Chybí ID', 200);
    if (!in_array($user['role'], ['admin', 'manazer'], true) && !auth_has_opravneni($user, 'potvrzeni_rezervace')) {
        api_response(false, null, 'Nemáte oprávnění potvrzovat rezervace.', 200);
    }
    $rez = db_row(
        "SELECT r.stav, r.pocet_noci, r.cena_zaklad, r.cena_upravena, p.typ_id
         FROM rezervace r
         JOIN pokoje p ON p.id = r.pokoj_id
         WHERE r.id = ?",
        [$id]
    );
    if (!$rez) api_response(false, null, 'Rezervace nenalezena', 200);
    if ($rez['stav'] !== 'ceka') api_response(false, null, 'Rezervace není ve stavu Čeká.', 200);

    // Přiřadit pokoj pokud byl vybrán
    $pokoj_id = (int)($input['pokoj_id'] ?? 0);
    if ($pokoj_id) {
        $pokoj = db_row('SELECT id, typ_id FROM pokoje WHERE id = ? AND aktivni = 1', [$pokoj_id]);
        if (!$pokoj) api_response(false, null, 'Pokoj nenalezen', 200);

        // Pokud zaměstnanec vybírá pokoj jiného (dražšího) typu — vyžádat schválení manažera
        if ($user['role'] === 'zamestnanec' && (int)$pokoj['typ_id'] !== (int)$rez['typ_id']) {
            $stara_cena = $rez['cena_upravena'] !== null ? (float)$rez['cena_upravena'] : (float)$rez['cena_zaklad'];
            $cena_za_noc_novy_typ = (float)db_val('SELECT cena_za_noc FROM typy_pokoju WHERE id = ?', [$pokoj['typ_id']]);
            $spravna_cena_typu    = round($cena_za_noc_novy_typ * (int)$rez['pocet_noci'], 2);

            if ($spravna_cena_typu > $stara_cena + 0.01) {
                db_query(
                    "UPDATE rezervace SET
                        pokoj_zadost_pokoj_id = ?, pokoj_zadost_cena_typu = ?,
                        pokoj_zadost_stav = 'ceka', pokoj_zadost_user_id = ?
                     WHERE id = ?",
                    [$pokoj_id, $spravna_cena_typu, $user['id'], $id]
                );
                try {
                    require_once __DIR__ . '/../includes/mailer.php';
                    odeslat_zadost_zmena_pokoje($id, $user, $pokoj_id, $stara_cena, $spravna_cena_typu);
                } catch (\Throwable $e) {
                    error_log('[Mailer] Chyba při odesílání žádosti o pokoj: ' . $e->getMessage());
                }
                api_response(false, null,
                    'Vybraný pokoj je dražšího typu — žádost o schválení byla odeslána manažerovi. ' .
                    'Rezervaci potvrďte až po schválení, nebo zvolte pokoj odpovídajícího typu.',
                    200
                );
            }
        }

        db_query('UPDATE rezervace SET pokoj_id = ?, stav = ? WHERE id = ?', [$pokoj_id, 'potvrzena', $id]);
    } else {
        db_query('UPDATE rezervace SET stav = ? WHERE id = ?', ['potvrzena', $id]);
    }

    // Odeslat potvrzovací e-mail zákazníkovi
    try {
        require_once __DIR__ . '/../includes/mailer.php';
        odeslat_potvrzeni_potvrzeno($id);
    } catch (\Throwable $e) {
        error_log('[Mailer] Chyba při odesílání potvrzení: ' . $e->getMessage());
    }

    api_response(true, null);
}

// ============================================================
//  ODEBRÁNÍ DOPLŇKU Z REZERVACE
// ============================================================
function rez_odebrat_doplnek(array $user, int $id, array $input): never {
    if (!$id) api_response(false, null, 'Chybí ID rezervace', 200);
    if (!auth_has_opravneni($user, 'zmena_rezervace') && !in_array($user['role'], ['admin','manazer'], true)) {
        api_response(false, null, 'Nedostatečná oprávnění', 200);
    }
    $nazev = trim($input['nazev'] ?? '');
    if (!$nazev) api_response(false, null, 'Chybí název doplňku', 200);

    // Najít a smazat doplněk
    $dp = db_row('SELECT id, cena_celkem FROM rezervace_doplnky WHERE rezervace_id = ? AND nazev = ? LIMIT 1', [$id, $nazev]);
    if (!$dp) api_response(false, null, 'Doplněk nenalezen', 200);

    $rez_pred = db_row('SELECT cena_zaklad, cena_upravena FROM rezervace WHERE id = ?', [$id]);
    $stara_cena_dp_suma = (float)db_val('SELECT COALESCE(SUM(cena_celkem),0) FROM rezervace_doplnky WHERE rezervace_id = ?', [$id]);
    $stara_cena = $rez_pred['cena_upravena'] !== null
        ? (float)$rez_pred['cena_upravena']
        : (float)$rez_pred['cena_zaklad'] + $stara_cena_dp_suma;

    db_query('DELETE FROM rezervace_doplnky WHERE id = ?', [$dp['id']]);

    // Přepočítat cenu rezervace
    $nova_cena_dp = db_val('SELECT COALESCE(SUM(cena_celkem),0) FROM rezervace_doplnky WHERE rezervace_id = ?', [$id]);
    $cena_zaklad  = db_val('SELECT cena_zaklad FROM rezervace WHERE id = ?', [$id]);
    $nova_cena    = (float)$cena_zaklad + (float)$nova_cena_dp;
    db_query('UPDATE rezervace SET cena_upravena = ? WHERE id = ?', [$nova_cena, $id]);

    if (abs($nova_cena - $stara_cena) >= 0.01) {
        try {
            require_once __DIR__ . '/../includes/mailer.php';
            odeslat_zmenu_ceny_pokoje($id, $stara_cena, $nova_cena, 'duvod_doplnek_odebran', $nazev, 'odebrana', (float)$dp['cena_celkem']);
        } catch (\Throwable $e) {
            error_log('[Mailer] Chyba při odesílání změny ceny (odebrání doplňku): ' . $e->getMessage());
        }
    }

    api_response(true, null);
}

// ============================================================
//  PŘIDÁNÍ DOPLŇKU K REZERVACI
// ============================================================
function rez_pridat_doplnek(array $user, int $id, array $input): never {
    if (!$id) api_response(false, null, 'Chybí ID rezervace', 200);
    if (!auth_has_opravneni($user, 'zmena_rezervace') && !in_array($user['role'], ['admin','manazer'], true)) {
        api_response(false, null, 'Nedostatečná oprávnění', 200);
    }
    $doplnek_id   = (int)($input['doplnek_id'] ?? 0);
    $nazev        = trim($input['nazev'] ?? '');
    $cena         = (float)($input['cena'] ?? 0);
    $typ          = $input['typ_uctovani'] ?? 'jednorazove';
    $cena_celkem  = (float)($input['cena_celkem'] ?? $cena);

    if (!$doplnek_id || !$nazev) api_response(false, null, 'Chybí údaje doplňku', 200);

    $rez = db_row('SELECT pocet_noci, pocet_hostu, cena_zaklad, cena_upravena FROM rezervace WHERE id = ?', [$id]);
    if (!$rez) api_response(false, null, 'Rezervace nenalezena', 200);

    $stara_cena_dp_suma = (float)db_val('SELECT COALESCE(SUM(cena_celkem),0) FROM rezervace_doplnky WHERE rezervace_id = ?', [$id]);
    $stara_cena = $rez['cena_upravena'] !== null
        ? (float)$rez['cena_upravena']
        : (float)$rez['cena_zaklad'] + $stara_cena_dp_suma;

    $pocet_noci = in_array($typ, ['za_noc', 'za_osobu_noc'], true) ? (int)$rez['pocet_noci'] : 1;
    $multiplikator_hostu = $typ === 'za_osobu_noc' ? (int)$rez['pocet_hostu'] : 1;
    $celkem     = $cena * $pocet_noci * $multiplikator_hostu;

    db_query(
        'INSERT INTO rezervace_doplnky (rezervace_id, doplnek_id, nazev, cena, typ_uctovani, pocet_noci, cena_celkem)
         VALUES (?, ?, ?, ?, ?, ?, ?)',
        [$id, $doplnek_id, $nazev, $cena, $typ, $pocet_noci, $celkem]
    );

    // Přepočítat cenu
    $nova_cena_dp = db_val('SELECT COALESCE(SUM(cena_celkem),0) FROM rezervace_doplnky WHERE rezervace_id = ?', [$id]);
    $cena_zaklad  = db_val('SELECT cena_zaklad FROM rezervace WHERE id = ?', [$id]);
    $nova_cena    = (float)$cena_zaklad + (float)$nova_cena_dp;
    db_query('UPDATE rezervace SET cena_upravena = ? WHERE id = ?', [$nova_cena, $id]);

    if (abs($nova_cena - $stara_cena) >= 0.01) {
        try {
            require_once __DIR__ . '/../includes/mailer.php';
            odeslat_zmenu_ceny_pokoje($id, $stara_cena, $nova_cena, 'duvod_doplnek_pridan', $nazev, 'pridana', $celkem);
        } catch (\Throwable $e) {
            error_log('[Mailer] Chyba při odesílání změny ceny (přidání doplňku): ' . $e->getMessage());
        }
    }

    api_response(true, null);
}

// ============================================================
//  ÚPRAVA ÚDAJŮ HOSTA
// ============================================================
function rez_upravit_hosta(array $user, int $id, array $input): never {
    if (!$id) api_response(false, null, 'Chybí ID', 200);
    if (!auth_has_opravneni($user, 'zmena_rezervace') && !in_array($user['role'], ['admin','manazer'], true)) {
        api_response(false, null, 'Nedostatečná oprávnění', 200);
    }
    $rez = db_row('SELECT id FROM rezervace WHERE id = ?', [$id]);
    if (!$rez) api_response(false, null, 'Rezervace nenalezena', 200);

    $jmeno    = trim($input['jmeno']    ?? '');
    $prijmeni = trim($input['prijmeni'] ?? '');
    $email    = trim($input['email']    ?? '');

    if (!$jmeno || !$prijmeni)     api_response(false, null, 'Jméno a příjmení jsou povinné.', 200);
    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) api_response(false, null, 'Neplatný e-mail.', 200);

    $na_firmu = !empty($input['na_firmu']) ? 1 : 0;
    $firma    = trim($input['firma'] ?? '');

    // Validace - pokud na firmu, musí být název
    if ($na_firmu && !$firma) {
        api_response(false, null, 'Při fakturaci na firmu zadejte název firmy.', 200);
    }

    db_query(
        'UPDATE rezervace SET jmeno=?, prijmeni=?, email=?, telefon=?,
         poznamka=?, faktura_ulice=?, faktura_psc=?, faktura_mesto=?,
         na_firmu=?, firma=?, ico=?, dic=?
         WHERE id=?',
        [
            $jmeno, $prijmeni, $email,
            trim($input['telefon']       ?? ''),
            trim($input['poznamka']      ?? ''),
            trim($input['faktura_ulice'] ?? ''),
            trim($input['faktura_psc']   ?? ''),
            trim($input['faktura_mesto'] ?? ''),
            $na_firmu,
            $firma,
            trim($input['ico']           ?? ''),
            trim($input['dic']           ?? ''),
            $id,
        ]
    );

    api_response(true, null);
}

// ============================================================
//  ZMĚNA PŘIŘAZENÉHO POKOJE
// ============================================================
function rez_zmenit_pokoj(array $user, int $id, array $input): never {
    if (!$id) api_response(false, null, 'Chybí ID', 200);
    if (!in_array($user['role'], ['admin', 'manazer'], true) && !auth_has_opravneni($user, 'zmena_terminu')) {
        api_response(false, null, 'Nemáte oprávnění měnit pokoj.', 200);
    }
    $rez = db_row(
        "SELECT r.pokoj_id, r.pocet_noci, r.cena_zaklad, r.cena_upravena, p.typ_id, r.stav
         FROM rezervace r
         JOIN pokoje p ON p.id = r.pokoj_id
         WHERE r.id = ?",
        [$id]
    );
    if (!$rez) api_response(false, null, 'Rezervace nenalezena', 200);
    if ($rez['stav'] === 'zrusena') api_response(false, null, 'Zrušenou rezervaci nelze měnit.', 200);

    $novy_pokoj_id = (int)($input['pokoj_id'] ?? 0);
    if (!$novy_pokoj_id) api_response(false, null, 'Chybí ID nového pokoje.', 200);

    $pokoj = db_row('SELECT id, typ_id FROM pokoje WHERE id = ? AND aktivni = 1', [$novy_pokoj_id]);
    if (!$pokoj) api_response(false, null, 'Pokoj nenalezen.', 200);

    $stara_cena = $rez['cena_upravena'] !== null ? (float)$rez['cena_upravena'] : (float)$rez['cena_zaklad'];

    // Skutečná cena odpovídající novému typu pokoje (pro kontrolu neoprávněné slevy)
    $cena_za_noc_novy_typ = (float)db_val('SELECT cena_za_noc FROM typy_pokoju WHERE id = ?', [$pokoj['typ_id']]);
    $spravna_cena_typu    = round($cena_za_noc_novy_typ * (int)$rez['pocet_noci'], 2);

    $nova_cena_vstup = $input['nova_cena'] ?? null;
    $cena_zmenena    = false;
    $nova_cena       = $stara_cena;

    // Zaměstnanec ponechává starou (nižší) cenu, ačkoliv nový typ je dražší — vyžaduje schválení
    if (
        $user['role'] === 'zamestnanec'
        && $nova_cena_vstup === null
        && $spravna_cena_typu > $stara_cena + 0.01
    ) {
        db_query(
            "UPDATE rezervace SET
                pokoj_zadost_pokoj_id = ?, pokoj_zadost_cena_typu = ?,
                pokoj_zadost_stav = 'ceka', pokoj_zadost_user_id = ?
             WHERE id = ?",
            [$novy_pokoj_id, $spravna_cena_typu, $user['id'], $id]
        );
        try {
            require_once __DIR__ . '/../includes/mailer.php';
            odeslat_zadost_zmena_pokoje($id, $user, $novy_pokoj_id, $stara_cena, $spravna_cena_typu);
        } catch (\Throwable $e) {
            error_log('[Mailer] Chyba při odesílání žádosti o pokoj: ' . $e->getMessage());
        }
        api_response(true, ['zadost' => true]);
    }

    if ($nova_cena_vstup !== null) {
        $nova_cena = round((float)$nova_cena_vstup, 2);
        db_query('UPDATE rezervace SET pokoj_id = ?, cena_zaklad = ?, cena_upravena = NULL WHERE id = ?',
            [$novy_pokoj_id, $nova_cena, $id]);
        $cena_zmenena = abs($nova_cena - $stara_cena) >= 0.01;
    } else {
        db_query('UPDATE rezervace SET pokoj_id = ? WHERE id = ?', [$novy_pokoj_id, $id]);
    }

    // Notifikovat zákazníka pouze pokud se cena skutečně změnila
    if ($cena_zmenena) {
        try {
            require_once __DIR__ . '/../includes/mailer.php';
            odeslat_zmenu_ceny_pokoje($id, $stara_cena, $nova_cena);
        } catch (\Throwable $e) {
            error_log('[Mailer] Chyba při odesílání změny ceny: ' . $e->getMessage());
        }
    }

    api_response(true, null);
}

// ------------------------------------------------------------
//  SCHVÁLENÍ / ZAMÍTNUTÍ ŽÁDOSTI O ZMĚNU POKOJE SE SLEVOU
// ------------------------------------------------------------
function rez_schvalit_pokoj(array $user, int $id): never {
    if (!in_array($user['role'], ['admin','manazer'], true)) {
        api_response(false, null, 'Pouze manažer může schvalovat.', 200);
    }
    $rez = db_row(
        "SELECT pokoj_zadost_pokoj_id, pokoj_zadost_cena_typu, cena_zaklad, cena_upravena
         FROM rezervace WHERE id = ? AND pokoj_zadost_stav = 'ceka'",
        [$id]
    );
    if (!$rez) api_response(false, null, 'Žádná čekající žádost.', 200);

    $stara_cena = $rez['cena_upravena'] !== null ? (float)$rez['cena_upravena'] : (float)$rez['cena_zaklad'];
    $nova_pokoj_id = (int)$rez['pokoj_zadost_pokoj_id'];

    db_query(
        "UPDATE rezervace SET pokoj_id = ?, pokoj_zadost_stav = 'schvaleno' WHERE id = ?",
        [$nova_pokoj_id, $id]
    );

    api_response(true, null);
}

function rez_zamitnout_pokoj(array $user, int $id, array $input): never {
    if (!in_array($user['role'], ['admin','manazer'], true)) {
        api_response(false, null, 'Pouze manažer může zamítat.', 200);
    }
    $rez = db_row("SELECT pokoj_zadost_user_id FROM rezervace WHERE id = ? AND pokoj_zadost_stav = 'ceka'", [$id]);
    if (!$rez) api_response(false, null, 'Žádná čekající žádost.', 200);

    $poznamka = trim($input['poznamka'] ?? '');
    db_query("UPDATE rezervace SET pokoj_zadost_stav = 'zamitnuto', pokoj_zadost_poznamka = ? WHERE id = ?",
        [$poznamka ?: null, $id]);
    api_response(true, null);
}

Youez - 2016 - github.com/yon3zu
LinuXploit