<?php
require_once __DIR__ . '/../app/helpers.php';
require_once __DIR__ . '/../app/db.php';
require_once __DIR__ . '/../accounts/account_lib.php';
require_once __DIR__ . '/../app/Services/AccountingService.php';

function hotel_table_exists(PDO $pdo, string $table): bool {
  $st = $pdo->prepare("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?");
  $st->execute([$table]);
  return (int)$st->fetchColumn() > 0;
}

function hotel_col_exists(PDO $pdo, string $table, string $col): bool {
  $st = $pdo->prepare("SELECT COUNT(*) FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = ? AND column_name = ?");
  $st->execute([$table, $col]);
  return (int)$st->fetchColumn() > 0;
}

function hotel_add_column_if_missing(PDO $pdo, string $table, string $col, string $definition): void {
  if (!hotel_table_exists($pdo, $table) || hotel_col_exists($pdo, $table, $col)) return;
  $pdo->exec("ALTER TABLE `{$table}` ADD COLUMN `{$col}` {$definition}");
}

function hotel_ensure_schema(PDO $pdo): void {
  $pdo->exec("CREATE TABLE IF NOT EXISTS hotel_hotels (
    id INT AUTO_INCREMENT PRIMARY KEY,
    company_id INT NOT NULL,
    code VARCHAR(50) NULL,
    name VARCHAR(190) NOT NULL,
    ownership_type ENUM('OWNED','THIRD_PARTY') NOT NULL DEFAULT 'THIRD_PARTY',
    city VARCHAR(120) NULL,
    address VARCHAR(255) NULL,
    contact_person VARCHAR(120) NULL,
    phone VARCHAR(60) NULL,
    email VARCHAR(190) NULL,
    status ENUM('ACTIVE','INACTIVE') NOT NULL DEFAULT 'ACTIVE',
    notes TEXT NULL,
    created_by INT NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_hotel_hotels_company (company_id),
    INDEX idx_hotel_hotels_status (company_id, status)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

  $pdo->exec("CREATE TABLE IF NOT EXISTS hotel_rooms (
    id INT AUTO_INCREMENT PRIMARY KEY,
    company_id INT NOT NULL,
    hotel_id INT NOT NULL,
    room_no VARCHAR(60) NOT NULL,
    room_name VARCHAR(120) NULL,
    room_type VARCHAR(120) NULL,
    ownership_type ENUM('OWNED','THIRD_PARTY') NOT NULL DEFAULT 'THIRD_PARTY',
    capacity_adults INT NOT NULL DEFAULT 2,
    capacity_children INT NOT NULL DEFAULT 0,
    base_cost DECIMAL(14,2) NOT NULL DEFAULT 0,
    base_price DECIMAL(14,2) NOT NULL DEFAULT 0,
    status ENUM('AVAILABLE','OUT_OF_SERVICE','INACTIVE') NOT NULL DEFAULT 'AVAILABLE',
    notes TEXT NULL,
    created_by INT NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_hotel_rooms_company (company_id),
    INDEX idx_hotel_rooms_hotel (hotel_id),
    INDEX idx_hotel_rooms_status (company_id, status)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

  $pdo->exec("CREATE TABLE IF NOT EXISTS hotel_bookings (
    id INT AUTO_INCREMENT PRIMARY KEY,
    company_id INT NOT NULL,
    request_no VARCHAR(60) NOT NULL,
    customer_id INT NULL,
    hotel_id INT NOT NULL,
    room_id INT NULL,
    request_date DATE NOT NULL,
    checkin_date DATE NOT NULL,
    checkout_date DATE NOT NULL,
    nights INT NOT NULL DEFAULT 1,
    adults_count INT NOT NULL DEFAULT 1,
    children_count INT NOT NULL DEFAULT 0,
    meal_plan VARCHAR(100) NULL,
    booking_type ENUM('ROOM','PACKAGE') NOT NULL DEFAULT 'ROOM',
    payment_type ENUM('CASH','CREDIT') NOT NULL DEFAULT 'CREDIT',
    status ENUM('PENDING','PRICED','CONFIRMED','CANCELLED','CHECKED_IN','CHECKED_OUT') NOT NULL DEFAULT 'PENDING',
    cost_price DECIMAL(14,2) NOT NULL DEFAULT 0,
    sale_price DECIMAL(14,2) NOT NULL DEFAULT 0,
    total_cost DECIMAL(14,2) NOT NULL DEFAULT 0,
    total_sale DECIMAL(14,2) NOT NULL DEFAULT 0,
    voucher_notes TEXT NULL,
    notes TEXT NULL,
    posted_entry_id INT NULL,
    created_by INT NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NULL DEFAULT NULL,
    INDEX idx_hotel_bookings_company (company_id),
    INDEX idx_hotel_bookings_dates (company_id, request_date, checkin_date, checkout_date),
    INDEX idx_hotel_bookings_customer (customer_id),
    INDEX idx_hotel_bookings_status (company_id, status)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

  $pdo->exec("CREATE TABLE IF NOT EXISTS hotel_receipts (
    id INT AUTO_INCREMENT PRIMARY KEY,
    company_id INT NOT NULL,
    receipt_no VARCHAR(60) NOT NULL,
    booking_id INT NULL,
    customer_id INT NULL,
    receipt_date DATE NOT NULL,
    cash_account_id INT NOT NULL,
    amount DECIMAL(14,2) NOT NULL DEFAULT 0,
    payment_method ENUM('CASH','BANK') NOT NULL DEFAULT 'CASH',
    notes TEXT NULL,
    posted_entry_id INT NULL,
    created_by INT NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_hotel_receipts_company (company_id),
    INDEX idx_hotel_receipts_date (company_id, receipt_date),
    INDEX idx_hotel_receipts_booking (booking_id)
  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

  hotel_add_column_if_missing($pdo, 'customers', 'account_id', 'INT NULL');
  hotel_add_column_if_missing($pdo, 'customers', 'address', 'VARCHAR(255) NULL');
  hotel_add_column_if_missing($pdo, 'customers', 'code', 'VARCHAR(50) NULL');
  hotel_add_column_if_missing($pdo, 'customers', 'opening_balance', 'DECIMAL(14,2) NOT NULL DEFAULT 0');
  hotel_add_column_if_missing($pdo, 'customers', 'status', "ENUM('ACTIVE','INACTIVE') NOT NULL DEFAULT 'ACTIVE'");
}

function hotel_status_badge(string $status): string {
  return match($status){
    'PENDING' => 'bg-secondary-subtle text-secondary border',
    'PRICED' => 'bg-info-subtle text-info border',
    'CONFIRMED' => 'bg-success-subtle text-success border',
    'CHECKED_IN' => 'bg-primary-subtle text-primary border',
    'CHECKED_OUT' => 'bg-dark-subtle text-dark border',
    'CANCELLED' => 'bg-danger-subtle text-danger border',
    default => 'bg-light text-dark border',
  };
}

function hotel_status_label(string $status): string {
  return match($status){
    'PENDING' => 'طلب جديد',
    'PRICED' => 'تم التسعير',
    'CONFIRMED' => 'مؤكد',
    'CHECKED_IN' => 'تم الدخول',
    'CHECKED_OUT' => 'تم الخروج',
    'CANCELLED' => 'ملغي',
    default => $status,
  };
}

function hotel_ownership_label(string $value): string {
  return $value === 'OWNED' ? 'مملوكة' : 'غير مملوكة';
}

function hotel_room_status_label(string $value): string {
  return match($value){
    'AVAILABLE' => 'متاحة',
    'OUT_OF_SERVICE' => 'خارج الخدمة',
    'INACTIVE' => 'موقوفة',
    default => $value,
  };
}

function hotel_next_code(PDO $pdo, string $table, string $field, int $companyId, string $prefix): string {
  $st = $pdo->prepare("SELECT {$field} FROM `{$table}` WHERE company_id=? ORDER BY id DESC LIMIT 1");
  $st->execute([$companyId]);
  $last = (string)($st->fetchColumn() ?: '');
  if (preg_match('/(\d+)$/', $last, $m)) {
    return $prefix . str_pad((string)((int)$m[1] + 1), 5, '0', STR_PAD_LEFT);
  }
  return $prefix . '00001';
}

function hotel_find_or_create_account(PDO $pdo, int $companyId, string $code, string $name, string $type, ?string $parentCode = null, bool $isCash = false): int {
  $existing = account_id_by_code($pdo, $companyId, $code);
  if ($existing) return $existing;

  $parentId = null;
  if ($parentCode) {
    $parentId = account_id_by_code($pdo, $companyId, $parentCode);
  }
  if (!$parentId) {
    $roots = [
      'ASSET' => '1000',
      'LIABILITY' => '2000',
      'EQUITY' => '3000',
      'REVENUE' => '4000',
      'EXPENSE' => '5000',
    ];
    $parentId = account_id_by_code($pdo, $companyId, $roots[$type] ?? '1000');
  }

  $stmt = $pdo->prepare("INSERT INTO accounts (company_id, code, name, type, normal_side, parent_id, is_cash, is_locked, is_active)
                         VALUES (?,?,?,?,?,?,?,?,?)");
  $stmt->execute([
    $companyId,
    $code,
    $name,
    $type,
    account_normal_side($type),
    $parentId,
    $isCash ? 1 : 0,
    0,
    1
  ]);
  return (int)$pdo->lastInsertId();
}

function hotel_default_accounts(PDO $pdo, int $companyId): array {
  hotel_find_or_create_account($pdo, $companyId, '4110', 'إيرادات حجوزات الفنادق', 'REVENUE', '4000');
  hotel_find_or_create_account($pdo, $companyId, '1140', 'العملاء', 'ASSET', '1100');
  $cashId = account_id_by_code($pdo, $companyId, '1110') ?: account_id_by_code($pdo, $companyId, '1120');
  if (!$cashId) {
    $cashId = hotel_find_or_create_account($pdo, $companyId, '1110', 'الصندوق', 'ASSET', '1100', true);
  }
  return [
    'cash_id' => (int)$cashId,
    'ar_id' => (int)(account_id_by_code($pdo, $companyId, '1140') ?: 0),
    'revenue_id' => (int)(account_id_by_code($pdo, $companyId, '4110') ?: 0),
  ];
}

function hotel_create_booking_journal(PDO $pdo, int $companyId, int $bookingId, int $userId = 0): int {
  hotel_ensure_schema($pdo);
  $svc = new AccountingService($pdo);
  $q = $pdo->prepare("SELECT b.*, c.account_id AS customer_account_id, c.full_name AS customer_name, h.name AS hotel_name, r.room_no
                      FROM hotel_bookings b
                      LEFT JOIN customers c ON c.id=b.customer_id AND c.company_id=b.company_id
                      JOIN hotel_hotels h ON h.id=b.hotel_id AND h.company_id=b.company_id
                      LEFT JOIN hotel_rooms r ON r.id=b.room_id AND r.company_id=b.company_id
                      WHERE b.id=? AND b.company_id=? LIMIT 1");
  $q->execute([$bookingId, $companyId]);
  $r = $q->fetch(PDO::FETCH_ASSOC);
  if (!$r) throw new RuntimeException('طلب الحجز غير موجود.');
  if (!empty($r['posted_entry_id'])) return (int)$r['posted_entry_id'];

  $acc = hotel_default_accounts($pdo, $companyId);
  $debitAccount = (($r['payment_type'] ?? 'CREDIT') === 'CASH') ? $acc['cash_id'] : (int)($r['customer_account_id'] ?: $acc['ar_id']);
  $amount = (float)($r['total_sale'] ?? 0);
  if ($amount <= 0) throw new RuntimeException('قيمة الحجز غير صالحة للترحيل.');
  if (!$debitAccount || !$acc['revenue_id']) throw new RuntimeException('حسابات ربط حجوزات الفنادق غير مكتملة.');

  $memo = 'حجز فندقي ' . ($r['request_no'] ?: ('#'.$bookingId)) . ' - ' . ($r['hotel_name'] ?? '');
  $lines = [
    ['account_id' => $debitAccount, 'debit' => $amount, 'credit' => 0, 'description' => (($r['payment_type'] ?? 'CREDIT') === 'CASH' ? 'تحصيل نقدي/فوري' : 'مستحق على عميل')],
    ['account_id' => $acc['revenue_id'], 'debit' => 0, 'credit' => $amount, 'description' => 'إيراد حجز فندقي'],
  ];
  $entryId = $svc->createManualJournal($companyId, (string)$r['request_date'], 'HBK-'.$bookingId, $memo, $lines, $userId, 'MANUAL', $bookingId);
  $pdo->prepare("UPDATE hotel_bookings SET posted_entry_id=? WHERE id=? AND company_id=?")->execute([$entryId, $bookingId, $companyId]);
  return $entryId;
}

function hotel_unpost_booking_journal(PDO $pdo, int $companyId, int $bookingId): void {
  $st = $pdo->prepare("SELECT posted_entry_id FROM hotel_bookings WHERE id=? AND company_id=?");
  $st->execute([$bookingId, $companyId]);
  $entryId = (int)($st->fetchColumn() ?: 0);
  if (!$entryId) return;
  $pdo->beginTransaction();
  try {
    $pdo->prepare("DELETE FROM journal_lines WHERE company_id=? AND entry_id=?")->execute([$companyId, $entryId]);
    $pdo->prepare("DELETE FROM journal_entries WHERE company_id=? AND id=?")->execute([$companyId, $entryId]);
    $pdo->prepare("UPDATE hotel_bookings SET posted_entry_id=NULL WHERE id=? AND company_id=?")->execute([$bookingId, $companyId]);
    $pdo->commit();
  } catch (Throwable $e) {
    if ($pdo->inTransaction()) $pdo->rollBack();
    throw $e;
  }
}

function hotel_create_receipt_journal(PDO $pdo, int $companyId, int $receiptId, int $userId = 0): int {
  hotel_ensure_schema($pdo);
  $svc = new AccountingService($pdo);
  $q = $pdo->prepare("SELECT r.*, c.account_id AS customer_account_id, c.full_name AS customer_name
                      FROM hotel_receipts r
                      LEFT JOIN customers c ON c.id=r.customer_id AND c.company_id=r.company_id
                      WHERE r.id=? AND r.company_id=? LIMIT 1");
  $q->execute([$receiptId, $companyId]);
  $r = $q->fetch(PDO::FETCH_ASSOC);
  if (!$r) throw new RuntimeException('التحصيل غير موجود.');
  if (!empty($r['posted_entry_id'])) return (int)$r['posted_entry_id'];

  $acc = hotel_default_accounts($pdo, $companyId);
  $cashId = (int)($r['cash_account_id'] ?: $acc['cash_id']);
  $creditId = (int)($r['customer_account_id'] ?: $acc['ar_id']);
  $amount = (float)($r['amount'] ?? 0);
  if ($amount <= 0) throw new RuntimeException('قيمة التحصيل غير صالحة.');
  if (!$cashId || !$creditId) throw new RuntimeException('حسابات التحصيل غير مكتملة.');

  $memo = 'تحصيل حجز فندقي ' . ($r['receipt_no'] ?: ('#'.$receiptId));
  $lines = [
    ['account_id' => $cashId, 'debit' => $amount, 'credit' => 0, 'description' => 'تحصيل نقدية/بنك'],
    ['account_id' => $creditId, 'debit' => 0, 'credit' => $amount, 'description' => 'تسوية حساب عميل'],
  ];
  $entryId = $svc->createManualJournal($companyId, (string)$r['receipt_date'], 'HRC-'.$receiptId, $memo, $lines, $userId, 'MANUAL', $receiptId);
  $pdo->prepare("UPDATE hotel_receipts SET posted_entry_id=? WHERE id=? AND company_id=?")->execute([$entryId, $receiptId, $companyId]);
  return $entryId;
}

function hotel_unpost_receipt_journal(PDO $pdo, int $companyId, int $receiptId): void {
  $st = $pdo->prepare("SELECT posted_entry_id FROM hotel_receipts WHERE id=? AND company_id=?");
  $st->execute([$receiptId, $companyId]);
  $entryId = (int)($st->fetchColumn() ?: 0);
  if (!$entryId) return;
  $pdo->beginTransaction();
  try {
    $pdo->prepare("DELETE FROM journal_lines WHERE company_id=? AND entry_id=?")->execute([$companyId, $entryId]);
    $pdo->prepare("DELETE FROM journal_entries WHERE company_id=? AND id=?")->execute([$companyId, $entryId]);
    $pdo->prepare("UPDATE hotel_receipts SET posted_entry_id=NULL WHERE id=? AND company_id=?")->execute([$receiptId, $companyId]);
    $pdo->commit();
  } catch (Throwable $e) {
    if ($pdo->inTransaction()) $pdo->rollBack();
    throw $e;
  }
}
