<?php
ob_start();
session_start();

include_once("../config.php");
include_once("../functions.php");
if (!check_login()) {
  header("Location: " . WEB_URL . "logout.php");
  exit();
}

include_once(ROOT_PATH . 'partial/report_top_common.php');
include_once(ROOT_PATH . 'language/' . $lang_code_global . '/lang_unit_status_info.php');
include_once(ROOT_PATH . 'language/' . $lang_code_global . '/lang_common.php');

$get_data = get_input_serilization();

/* ------------------------- Helpers ------------------------- */
function e($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
function days_between_inclusive($start, $end){
  return max(0, (strtotime($end) - strtotime($start)) / 86400 + 1);
}
function overlap_days_inclusive($a_s,$a_e,$b_s,$b_e){
  $s = max(strtotime($a_s), strtotime($b_s));
  $e = min(strtotime($a_e), strtotime($b_e));
  return ($e >= $s) ? (($e - $s) / 86400 + 1) : 0;
}
function ymd_valid($d){
  return (bool)preg_match('/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/', $d);
}

/* ------------------------- Inputs ------------------------- */
$status_in = isset($get_data['status']) ? strtolower(trim($get_data['status'])) : '';
$month     = isset($get_data['month'])  ? trim($get_data['month'])             : '';
$mode      = isset($get_data['mode'])   ? strtolower(trim($get_data['mode']))  : '';
$year_in   = isset($get_data['year'])   ? (int)$get_data['year']               : 0;
$from_in   = isset($get_data['from'])   ? trim($get_data['from'])              : '';
$to_in     = isset($get_data['to'])     ? trim($get_data['to'])                : '';

if ($status_in === 'available') $status_in = 'vacant';

$today = date('Y-m-d');

/* Validate month (yyyy-mm) */
$month_valid = false; $month_start=''; $month_end='';
if ($month && preg_match('/^\d{4}-(0[1-9]|1[0-2])$/', $month)) {
  $month_valid = true;
  $month_start = $month . '-01';
  $month_end   = date('Y-m-t', strtotime($month_start));
}

/* ------------------------- Decide WINDOWS ------------------------- */
/*
  WINDOW (for “Booked” / “Available” buttons)
  - If month is given: that month.
  - Else if occupied (and no month): show lifetime booked range.
  - Else (status=all or vacant or none): today → +6 months.
*/
$chart_start = $today;
$chart_end   = date('Y-m-d', strtotime('+6 months'));
$window_label = '';

$need_lifetime = ($status_in === 'occupied' && !$month_valid);

/* YEAR window (for “All Year — Available & Booked”) */
$curY = (int)date('Y');
if ($year_in >= 1900 && $year_in <= 2100) {
  $year_start = sprintf('%04d-01-01', $year_in);
  $year_end   = sprintf('%04d-12-31', $year_in);
  $year_label = (string)$year_in;
} elseif (ymd_valid($from_in) && ymd_valid($to_in) && ($from_in <= $to_in)) {
  $year_start = $from_in;
  $year_end   = $to_in;
  $year_label = date('Y', strtotime($year_start)) === date('Y', strtotime($year_end))
                ? date('Y', strtotime($year_start))
                : (date('Y', strtotime($year_start)).'–'.date('Y', strtotime($year_end)));
} else {
  $year_start = $curY.'-01-01';
  $year_end   = $curY.'-12-31';
  $year_label = (string)$curY;
}

/* WINDOW logic */
if ($need_lifetime) {
  $stmt = $link->prepare("SELECT MIN(start_date) AS smin, MAX(end_date) AS emax FROM rent_tenant_unit_view");
  $stmt->execute();
  $res = $stmt->get_result();
  $row = $res->fetch_assoc();
  $stmt->close();
  if (!empty($row['smin']) && !empty($row['emax'])) {
    $chart_start = $row['smin'];
    $chart_end   = $row['emax'];
  }
} elseif ($month_valid) {
  $chart_start = $month_start;
  $chart_end   = $month_end;
}

/* Labels */
if ($month_valid) {
  $window_label = date('F Y', strtotime($chart_start));
} elseif ($need_lifetime) {
  $window_label = 'All Booked Dates (Lifetime)';
} else {
  $window_label = date('M j, Y', strtotime($chart_start)) . ' → ' . date('M j, Y', strtotime($chart_end));
}

/* ------------------------- Units query ------------------------- */
switch ($status_in) {
  case 'vacant':
    $units_sql = "SELECT *, uid FROM unoccupied_units_view";
    break;
  case 'occupied':
    $units_sql = "SELECT *, uid FROM occupied_units_view";
    break;
  default: // 'all' or empty
    $units_sql = "SELECT *, uid FROM unit_view";
    break;
}
$units_rs = mysqli_query($link, $units_sql);
$units = [];
while ($u = mysqli_fetch_assoc($units_rs)) $units[] = $u;

/* ------------------------- Span helpers ------------------------- */
function merge_spans(array $spans): array {
  usort($spans, fn($a,$b)=>strcmp($a['s'],$b['s']));
  $merged = [];
  foreach ($spans as $p) {
    if (empty($p['s']) || empty($p['e'])) continue;
    if (empty($merged)) { $merged[] = $p; continue; }
    $i = count($merged)-1;
    $L = &$merged[$i];
    $nextDay = date('Y-m-d', strtotime($L['e'].' +1 day'));
    if ($p['s'] <= $nextDay) {
      if ($p['e'] > $L['e']) $L['e'] = $p['e'];
    } else {
      $merged[] = $p;
    }
  }
  return $merged;
}
function clip_spans_to_window(array $spans, string $win_s, string $win_e): array {
  $out = [];
  $ws = strtotime($win_s); $we = strtotime($win_e);
  foreach ($spans as $sp) {
    $ss = strtotime($sp['s']); $ee = strtotime($sp['e']);
    if ($ee < $ws || $ss > $we) continue;
    $cs = max($ss, $ws); $ce = min($ee, $we);
    $out[] = ['s'=>date('Y-m-d',$cs), 'e'=>date('Y-m-d',$ce)];
  }
  return merge_spans($out);
}
function fetch_booked_spans_raw(mysqli $link, int $uid): array {
  $sql = "SELECT start_date AS s, end_date AS e FROM rent_tenant_unit_view WHERE uid = ? ORDER BY start_date ASC";
  $stmt = $link->prepare($sql);
  $stmt->bind_param('i', $uid);
  $stmt->execute();
  $res = $stmt->get_result();
  $rows = [];
  while ($r = $res->fetch_assoc()) {
    if ($r['s'] && $r['e']) $rows[] = $r;
  }
  $stmt->close();
  return merge_spans($rows);
}

/* ------------------------- Build month buckets ------------------------- */
/* WINDOW months */
$months = [];
$cursor = date('Y-m-01', strtotime($chart_start));
$end_first = date('Y-m-01', strtotime($chart_end));
while ($cursor <= $end_first) {
  $months[] = $cursor;
  $cursor = date('Y-m-01', strtotime($cursor . ' +1 month'));
}
if (empty($months)) $months[] = date('Y-m-01', strtotime($chart_start));

/* YEAR months (Jan–Dec for chosen year) */
$months_year = [];
$yc = date('Y-m-01', strtotime($year_start));
$end_y = date('Y-m-01', strtotime($year_end));
while ($yc <= $end_y) {
  $months_year[] = $yc;
  $yc = date('Y-m-01', strtotime($yc . ' +1 month'));
}
if (empty($months_year)) $months_year[] = date('Y-m-01', strtotime($year_start));

/* ------------------------- Build series + table ------------------------- */
$seriesBooked = [];
$seriesVacant = [];
$seriesYearBooked = [];
$seriesYearVacant = [];
$rows_view    = [];

foreach ($units as $row) {
  $uid   = (int)$row['uid'];
  $label = ($row['b_name'] ?? '') . ' • ' . ($row['unit_no'] ?? '');
  $raw_spans = fetch_booked_spans_raw($link, $uid);

  /* ===== WINDOW series ===== */
  $rowBooked = ['name' => $label, 'data' => []];
  $rowVacant = ['name' => $label, 'data' => []];

  foreach ($months as $m0) {
    $month_start_ts = strtotime($m0);
    $month_end_ts   = strtotime(date('Y-m-t', $month_start_ts));
    $cell_start = max($month_start_ts, strtotime($chart_start));
    $cell_end   = min($month_end_ts,   strtotime($chart_end));
    if ($cell_end < $cell_start) {
      $rowBooked['data'][] = ['x' => date('M Y', $month_start_ts), 'y' => null];
      $rowVacant['data'][] = ['x' => date('M Y', $month_start_ts), 'y' => null];
      continue;
    }
    $cell_days = ($cell_end - $cell_start) / 86400 + 1;

    $booked_days = 0;
    foreach ($raw_spans as $sp) {
      $booked_days += overlap_days_inclusive($sp['s'],$sp['e'], date('Y-m-d',$cell_start), date('Y-m-d',$cell_end));
    }
    $booked_days = min($booked_days, $cell_days);
    $vacant_days = max(0, $cell_days - $booked_days);

    $booked_pct = round(($cell_days > 0) ? ($booked_days * 100.0 / $cell_days) : 0, 1);
    $vacant_pct = round(($cell_days > 0) ? ($vacant_days * 100.0 / $cell_days) : 0, 1);

    $rowBooked['data'][] = ['x'=>date('M Y',$month_start_ts), 'y'=>$booked_pct, 'days'=>$booked_days, 'total'=>$cell_days];
    $rowVacant['data'][] = ['x'=>date('M Y',$month_start_ts), 'y'=>$vacant_pct, 'days'=>$vacant_days, 'total'=>$cell_days];
  }
  $seriesBooked[] = $rowBooked;
  $seriesVacant[] = $rowVacant;

  /* ===== YEAR series (Jan→Dec) ===== */
  $rowYearBooked = ['name' => $label, 'data' => []];
  $rowYearVacant = ['name' => $label, 'data' => []];

  foreach ($months_year as $m0) {
    $m_start_ts = strtotime($m0);
    $m_end_ts   = strtotime(date('Y-m-t', $m_start_ts));
    $cell_start = max($m_start_ts, strtotime($year_start));
    $cell_end   = min($m_end_ts,   strtotime($year_end));
    if ($cell_end < $cell_start) {
      $rowYearBooked['data'][] = ['x' => date('M Y', $m_start_ts), 'y' => null];
      $rowYearVacant['data'][] = ['x' => date('M Y', $m_start_ts), 'y' => null];
      continue;
    }
    $cell_days = ($cell_end - $cell_start) / 86400 + 1;

    $booked_days = 0;
    foreach ($raw_spans as $sp) {
      $booked_days += overlap_days_inclusive($sp['s'],$sp['e'], date('Y-m-d',$cell_start), date('Y-m-d',$cell_end));
    }
    $booked_days = min($booked_days, $cell_days);
    $vacant_days = max(0, $cell_days - $booked_days);

    $booked_pct = round(($cell_days > 0) ? ($booked_days * 100.0 / $cell_days) : 0, 1);
    $vacant_pct = round(($cell_days > 0) ? ($vacant_days * 100.0 / $cell_days) : 0, 1);

    $rowYearBooked['data'][] = ['x'=>date('M Y',$m_start_ts), 'y'=>$booked_pct, 'days'=>$booked_days, 'total'=>$cell_days];
    $rowYearVacant['data'][] = ['x'=>date('M Y',$m_start_ts), 'y'=>$vacant_pct, 'days'=>$vacant_days, 'total'=>$cell_days];
  }
  $seriesYearBooked[] = $rowYearBooked;
  $seriesYearVacant[] = $rowYearVacant;

  /* ===== TABLE (window + year) ===== */
  $booked_window = ($status_in === 'occupied' && !$month_valid)
                    ? $raw_spans
                    : clip_spans_to_window($raw_spans, $chart_start, $chart_end);
  $booked_year   = clip_spans_to_window($raw_spans, $year_start, $year_end);

  $fmtSpans = function(array $spans): string {
    if (empty($spans)) return 'None';
    $tmp = [];
    foreach ($spans as $b) {
      $sd = new DateTime($b['s']); $ed = new DateTime($b['e']);
      $tmp[] = ($b['s'] === $b['e']) ? $sd->format('j M Y') : $sd->format('j M Y') . ' – ' . $ed->format('j M Y');
    }
    return implode(', ', $tmp);
  };

  // Window available
  $avail_window_txt = '';
  if (!empty($booked_window)) {
    $free = [];
    $cur  = $chart_start;
    foreach ($booked_window as $b) {
      if ($cur < $b['s']) $free[] = ['s'=>$cur, 'e'=>date('Y-m-d', strtotime($b['s'].' -1 day'))];
      $cur = date('Y-m-d', strtotime($b['e'].' +1 day'));
    }
    if ($cur <= $chart_end) { $free[] = ['s'=>$cur, 'e'=>$chart_end]; }
    $avail_window_txt = empty($free) ? 'Fully Occupied' : $fmtSpans($free);
  } else {
    $avail_window_txt = ($chart_start && $chart_end) ? $fmtSpans([['s'=>$chart_start,'e'=>$chart_end]]) : 'None';
  }

  // Year available
  $avail_year_txt = '';
  if (!empty($booked_year)) {
    $free = [];
    $cur  = $year_start;
    foreach ($booked_year as $b) {
      if ($cur < $b['s']) $free[] = ['s'=>$cur, 'e'=>date('Y-m-d', strtotime($b['s'].' -1 day'))];
      $cur = date('Y-m-d', strtotime($b['e'].' +1 day'));
    }
    if ($cur <= $year_end) { $free[] = ['s'=>$cur, 'e'=>$year_end]; }
    $avail_year_txt = empty($free) ? 'Fully Occupied' : $fmtSpans($free);
  } else {
    $avail_year_txt = $fmtSpans([['s'=>$year_start,'e'=>$year_end]]);
  }

  $rows_view[] = [
    'b_name'            => $row['b_name'] ?? '',
    'floor'             => $row['floor']  ?? '',
    'unit_no'           => $row['unit_no']?? '',
    'd_rate'            => isset($row['d_rate']) ? (float)$row['d_rate'] : 0,
    'm_rate'            => isset($row['rate'])   ? (float)$row['rate']   : 0,
    'status'            => $row['status'] ?? '',
    'booked_window_txt' => $fmtSpans($booked_window),
    'booked_year_txt'   => $fmtSpans($booked_year),
    'avail_window_txt'  => $avail_window_txt,
    'avail_year_txt'    => $avail_year_txt
  ];
}
mysqli_close($link);

/* Table visibility flags */
$TABLE_SHOW_BOOKED    = ($status_in === 'occupied' || $status_in === '' || $status_in === 'all');
$TABLE_SHOW_AVAILABLE = ($status_in === 'vacant'   || $status_in === '' || $status_in === 'all');

/* Render pills */
function render_date_pills(string $text, string $type='free', int $limit=3): string {
  $text = trim($text);
  $icon = $type === 'booked' ? 'fa-times-circle' : 'fa-check-circle';
  $cls  = $type === 'booked' ? 'pill--booked'   : 'pill--free';

  if ($text === '' || $text === '-') {
    return '<div class="cell-pills"><span class="pill pill--muted"><i class="fa fa-calendar"></i> —</span></div>';
  }
  if (strcasecmp($text, 'None') === 0) {
    return '<div class="cell-pills"><span class="pill pill--ok"><i class="fa fa-check-circle"></i> None</span></div>';
  }
  if (strcasecmp($text, 'Fully Occupied') === 0) {
    return '<div class="cell-pills"><span class="pill pill--danger"><i class="fa fa-ban"></i> Fully Occupied</span></div>';
  }

  $parts_raw = array_map('trim', explode(',', $text));
  $parts = [];
  foreach ($parts_raw as $p) { if ($p !== '') $parts[] = $p; }

  $count = count($parts);
  $html  = '<div class="cell-pills" data-limit="'.(int)$limit.'" data-collapsed="1">';
  $i = 0;
  foreach ($parts as $p) {
    $i++;
    $extra = ($i > $limit) ? ' extra' : '';
    $html .= '<span class="pill '.$cls.$extra.'"><i class="fa '.$icon.'"></i> '.e($p).'</span>';
  }
  if ($count > $limit) {
    $remaining = $count - $limit;
    $html .= '<button type="button" class="pill-toggle" aria-expanded="false">+'.(int)$remaining.' more</button>';
  }
  $html .= '</div>';
  return $html;
}
?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title><?= e($building_name) ?> — Unit Occupancy Graph</title>
  <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
  <?php include_once(ROOT_PATH . '/partial/header_script.php'); ?>
  <script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>

  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
  <style>
    :root{
      /* Colors */
      --ink:#0b1324; --ink2:#2b3850; --muted:#64748b; --line:#e5e7eb;
      --brand:#2563eb; --brand-soft:#eef2ff;
      --ok:#16a34a; --danger:#dc2626;
      --soft:#f7f9fc; --soft2:#eef3ff;
      --chip:#f1f5f9; --chip-b:#d9e1ea;

      --free-bg:#ecfdf5; --free-b:#bbf7d0; --free-t:#065f46;
      --book-bg:#fef2f2; --book-b:#fecaca; --book-t:#7f1d1d;
      --muted-bg:#f8fafc; --muted-b:#e5e7eb;
      /* Typography scale */
      --fs-body:16px;
      --fs-sm:14.5px;
      --fs-md:15.5px;
      --fs-lg:18px;
      --fs-xl:22px;
      --fs-xxl:26px;
      /* Spacing scale */
      --sp-1:6px; --sp-2:10px; --sp-3:14px; --sp-4:18px; --sp-5:24px; --sp-6:32px;
      /* Radius */
      --r-sm:10px; --r-md:14px; --r-lg:18px; --r-xl:22px;
    }
    body, .content-wrapper, .btn, .badge {
      font-family:'Inter', system-ui, Segoe UI, Roboto, Helvetica, Arial;
      color:var(--ink2);
      background:linear-gradient(180deg, #f4f7fb, #f6f8ff);
      font-size:var(--fs-body);
      line-height:1.55;
    }
    .wrap{ max-width: 1400px; margin: var(--sp-5) auto 120px; padding: 0 var(--sp-3); }

    .card{
      border:1px solid var(--line); background:#fff; border-radius:var(--r-lg); overflow:hidden;
      box-shadow:0 20px 50px rgba(2,6,23,.08); margin-bottom:var(--sp-4);
    }
    .card-header{
      display:flex; align-items:flex-start; justify-content:space-between; gap:var(--sp-3);
      padding:var(--sp-4) var(--sp-5); background:linear-gradient(135deg,var(--soft),var(--soft2));
      border-bottom:1px solid var(--line);
    }
    .card-title{
      margin:0; font-weight:800; color:#0a1020; letter-spacing:.2px;
      font-size:var(--fs-xxl);
      display:flex; align-items:center; gap:var(--sp-2);
    }
    .card-title i{ opacity:.9; }
    .meta{ display:flex; gap:var(--sp-2); flex-wrap:wrap; font-size:var(--fs-sm); color:var(--muted); margin-top:var(--sp-2); }
    .chip{
      display:inline-flex; align-items:center; gap:var(--sp-2); padding:8px 12px;
      border:1px solid var(--chip-b); background:var(--chip); color:var(--ink2);
      border-radius:999px; font-weight:700; font-size:var(--fs-sm);
    }
    .chip.brand{ border-color:#c7d6ff; background:var(--brand-soft); color:#16309a; }

    .controls{ display:flex; gap:var(--sp-2); align-items:center; flex-wrap:wrap; }
    .btn{
      border-radius:12px; font-weight:800; padding:10px 14px; font-size:var(--fs-sm);
      border:1px solid var(--line); background:#fff; color:var(--ink2);
      transition: all .15s ease;
    }
    .btn:hover{ transform:translateY(-1px); box-shadow:0 6px 18px rgba(17,24,39,.08); }
    .btn-soft.active{ box-shadow:0 0 0 4px rgba(37,99,235,.18) inset; border-color:#9cc3ff; background:#fff; }
    .btn-success{ background:var(--ok); color:#fff; border-color:transparent; }
    .btn-success:hover{ filter:brightness(.97); }

    .legend{ font-size:var(--fs-sm); color:#5b6b82; display:flex; gap:var(--sp-3); align-items:center; margin-top:var(--sp-2); }
    .sw{ width:16px; height:16px; border-radius:4px; display:inline-block; box-shadow: inset 0 0 0 1px rgba(0,0,0,.06); }
    .sw.booked{ background:#ef4444; }
    .sw.vacant{ background:#10b981; }

    .chart-box{ padding:var(--sp-4) var(--sp-5) var(--sp-5); }
    .note{ font-size:var(--fs-sm); color:#6b7a91; margin-top:6px; }

    /* Split mode layout (side-by-side heatmaps) */
    .split-wrap{
      display:none; gap:var(--sp-3);
      grid-template-columns: 1fr 1fr;
    }
    .split-wrap.active{ display:grid; }
    .split-card{
      border:1px solid var(--line); background:#fff; border-radius:var(--r-md); padding:var(--sp-3) var(--sp-3) var(--sp-4);
      box-shadow:0 12px 28px rgba(2,6,23,.06);
    }
    .split-card > .title{
      font-weight:800; font-size:var(--fs-lg); color:var(--ink); margin:0 0 var(--sp-2);
    }

    /* ======= TABLE ======= */
    .table{ margin:0; font-size:var(--fs-md); background:#fff; }
    .table > thead > tr > th{
      position:sticky; top:0; z-index:2;
      font-weight:900; color:var(--ink); border-bottom:1px solid var(--line) !important; background:#fff;
      padding:14px 12px; letter-spacing:.2px; font-size:var(--fs-md);
    }
    .table > tbody > tr { transition: background .15s ease; }
    .table > tbody > tr:hover { background:#f9fbff; }
    .table > tbody > tr > td{ vertical-align:middle; padding:12px 12px; }

    .td-booked{ color:#7a1111; font-weight:700; }
    .td-free{ color:#0f5132; font-weight:700; }

    .cell-pills{
      display:flex; flex-wrap:wrap; gap:8px; align-items:flex-start; max-width: 100%;
    }
    .pill{
      display:inline-flex; align-items:center; gap:8px;
      padding:8px 12px; font-weight:800; font-size:14.5px;
      border-radius:999px; line-height:1.1; user-select:text;
      border:1px solid var(--muted-b); background:var(--muted-bg); color:#2f3a4e;
      white-space:nowrap;
    }
    .pill i{ opacity:.85; }
    .pill--free   { background:var(--free-bg);  border-color:var(--free-b); color:var(--free-t); }
    .pill--booked { background:var(--book-bg);  border-color:var(--book-b); color:var(--book-t); }
    .pill--ok     { background:#ecfdf5; border-color:#bbf7d0; color:#065f46; }
    .pill--danger { background:#fff1f1; border-color:#fecaca; color:#7f1d1d; }
    .pill--muted  { background:#f1f5f9; border-color:#e2e8f0; color:#334155; }

    .cell-pills[data-collapsed="1"] .pill.extra{ display:none; }
    .pill-toggle{
      border:1px dashed var(--chip-b); background:#fff; color:#475569;
      padding:7px 11px; border-radius:999px; font-weight:800; font-size:14px;
    }
    .pill-toggle:hover{ background:#f8fafc; }

    .empty-row{ color:#98a3b5; font-style:italic; text-align:center; font-size:var(--fs-md); padding:16px 0; }

    .print-fab{ position:fixed; right:16px; top:12px; z-index:9999; }
    @media print{
      .print-fab{ display:none !important; } body{ background:#fff; }
      .card{ box-shadow:none; border:1px solid #ddd; }
      .pill, .pill-toggle{ border:1px solid #999 !important; color:#000 !important; background:#fff !important; }
      .table > thead > tr > th{ position:static; }
    }

    /* Make ApexCharts labels more legible */
    .apexcharts-legend-text, .apexcharts-xaxis text, .apexcharts-yaxis text {
      font-size:14px !important;
      font-weight:600 !important;
      fill:#334155 !important;
    }
  </style>
  <script>
    function printContent(area, title) {
      $("#" + area).printThis({ pageTitle: title });
    }
  </script>
</head>
<body>

<section class="content">
  <div class="wrap" id="printable">
    <input type="hidden" id="web_url" value="<?= WEB_URL; ?>" />
    <?php include_once(ROOT_PATH . 'partial/report_top_title.php'); ?>

    <!-- Graph Card -->
    <div class="card">
      <div class="card-header">
        <div>
          <h3 class="card-title"><i class="fa fa-th"></i> Unit Occupancy Heatmap</h3>
          <div class="meta">
            <span class="chip brand">
              Scope: <?= e(ucfirst($status_in ?: 'all')); ?>
              <?= $month_valid ? ' • '.date('F Y', strtotime($chart_start)) : '' ?>
            </span>
            <span class="chip">Window: <?= e($window_label); ?></span>
            <span class="chip">Year: <?= e($year_label); ?></span>
            <span class="chip">Units: <?= count($units); ?></span>
          </div>
        </div>
        <div class="controls">
          <button id="btnBooked" class="btn btn-soft active"><i class="fa fa-circle" style="color:#ef4444;"></i> Booked (Window)</button>
          <button id="btnVacant" class="btn btn-soft"><i class="fa fa-circle" style="color:#10b981;"></i> Available (Window)</button>
          <button id="btnYearBooked" class="btn btn-soft"><i class="fa fa-calendar"></i> Year – Booked</button>
          <button id="btnYearVacant" class="btn btn-soft"><i class="fa fa-calendar-check-o"></i> Year – Available</button>
          <button id="btnYearBoth" class="btn btn-soft"><i class="fa fa-columns"></i> Year – Both (Merged)</button>
          <button id="btnYearBothSplit" class="btn btn-soft"><i class="fa fa-columns"></i> Year – Both (Side-by-side)</button>
          <button class="btn btn-success" onclick="printContent('printable','Unit Occupancy Heatmap')"><i class="fa fa-print"></i> Print</button>
        </div>
      </div>

      <div class="chart-box">
        <!-- Single heatmap container -->
        <div id="heatmapSingle" style="width:100%;"></div>

        <!-- Split heatmaps container -->
        <div id="heatmapSplitWrap" class="split-wrap">
          <div class="split-card">
            <div class="title">Year — Booked</div>
            <div id="heatmapSplitBooked"></div>
          </div>
          <div class="split-card">
            <div class="title">Year — Available</div>
            <div id="heatmapSplitVacant"></div>
          </div>
        </div>

        <div class="legend" id="legendNote">
          <span><span class="sw booked"></span> Higher % booked</span>
          <span><span class="sw vacant"></span> Higher % available</span>
          <span class="note">Cell value = % of days in the month</span>
        </div>
      </div>
    </div>

    <!-- Detailed dates table -->
    <div class="card">
      <div class="card-header">
        <h3 class="card-title"><i class="fa fa-table"></i> Detailed Dates</h3>
        <div class="controls">
          <button id="btnDatesWindow" class="btn btn-soft active"><i class="fa fa-filter"></i> Window Dates</button>
          <button id="btnDatesYear" class="btn btn-soft"><i class="fa fa-calendar"></i> Year Dates</button>
        </div>
      </div>
      <div class="chart-box">
        <div class="table-responsive">
          <table class="table table-bordered table-striped dt-responsive">
            <thead>
              <tr>
                <th>Block</th>
                <th><?= e($_data['text_2']); ?></th>
                <th><?= e($_data['text_3']); ?></th>
                <!-- <th>Daily Rate</th>
                <th>Monthly Rate</th> -->
                <th><?= e($_data['text_4']); ?></th>
                <?php if ($TABLE_SHOW_BOOKED): ?><th>Booked Dates</th><?php endif; ?>
                <?php if ($TABLE_SHOW_AVAILABLE): ?><th>Available Dates</th><?php endif; ?>
              </tr>
            </thead>
            <tbody>
              <?php if (empty($rows_view)): ?>
                <tr>
                  <td colspan="<?= 6 + ($TABLE_SHOW_BOOKED?1:0) + ($TABLE_SHOW_AVAILABLE?1:0); ?>" class="empty-row">
                    No units found for this scope.
                  </td>
                </tr>
              <?php else: ?>
                <?php foreach ($rows_view as $r): ?>
                  <tr>
                    <td><strong><?= e($r['b_name']); ?></strong></td>
                    <td><?= e($r['floor']); ?></td>
                    <td><strong><?= e($r['unit_no']); ?></strong></td>
                
                    <td><?= ($r['status']=='1') ? e($_data['text_5']) : e($_data['text_6']); ?></td>

                    <?php if ($TABLE_SHOW_BOOKED): ?>
                      <td class="td-booked">
                        <div class="pills-window">
                          <?= render_date_pills($r['booked_window_txt'], 'booked', 4); ?>
                        </div>
                        <div class="pills-year" style="display:none;">
                          <?= render_date_pills($r['booked_year_txt'], 'booked', 5); ?>
                        </div>
                      </td>
                    <?php endif; ?>

                    <?php if ($TABLE_SHOW_AVAILABLE): ?>
                      <td class="td-free">
                        <div class="pills-window">
                          <?= render_date_pills($r['avail_window_txt'], 'free', 5); ?>
                        </div>
                        <div class="pills-year" style="display:none;">
                          <?= render_date_pills($r['avail_year_txt'], 'free', 6); ?>
                        </div>
                      </td>
                    <?php endif; ?>
                  </tr>
                <?php endforeach; ?>
              <?php endif; ?>
            </tbody>
          </table>
        </div>
      </div>
    </div>

  </div>
</section>

<!-- Floating Print Button -->
<div class="print-fab">
  <button class="btn btn-success" onclick="printContent('printable','Unit Occupancy Heatmap')"><i class="fa fa-print"></i> Print</button>
</div>

<script>
  // Series from PHP
  const SERIES_BOOKED       = <?= json_encode($seriesBooked, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
  const SERIES_VACANT       = <?= json_encode($seriesVacant, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
  const SERIES_YEAR_BOOKED  = <?= json_encode($seriesYearBooked, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
  const SERIES_YEAR_VACANT  = <?= json_encode($seriesYearVacant, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES); ?>;
  const DEFAULT_MODE        = <?= json_encode($mode); ?>; // e.g. 'year-both', 'year-both-split', etc.

  // Categories
  const X_CATEGORIES      = (SERIES_BOOKED[0]      && SERIES_BOOKED[0].data)      ? SERIES_BOOKED[0].data.map(d => d.x) : [];
  const X_CATEGORIES_YEAR = (SERIES_YEAR_BOOKED[0] && SERIES_YEAR_BOOKED[0].data) ? SERIES_YEAR_BOOKED[0].data.map(d => d.x) : [];

  // Build "Year – Both (Merged)" (two rows per unit in a single heatmap)
  function buildYearBothMerged(booked, vacant){
    const combined = [];
    const n = booked.length;
    for (let i = 0; i < n; i++) {
      const b = JSON.parse(JSON.stringify(booked[i]));
      const v = JSON.parse(JSON.stringify(vacant[i]));
      b.name = b.name + ' — Booked';
      v.name = v.name + ' — Available';
      b.data = b.data.map(d => ({...d, y: (d.y == null ? null : Math.max(0, Math.min(100, d.y)))}));
      v.data = v.data.map(d => ({...d, y: (d.y == null ? null : 100 + Math.max(0, Math.min(100, d.y)))}));
      combined.push(b, v);
    }
    return combined;
  }
  const SERIES_YEAR_BOTH_MERGED = buildYearBothMerged(SERIES_YEAR_BOOKED, SERIES_YEAR_VACANT);

  // Base options (single heatmap) — slightly larger labels
  const baseOptions = {
    chart: {
      type: 'heatmap',
      height: Math.max(380, (SERIES_BOOKED.length * 32) + 160),
      toolbar: { show: false },
      fontFamily: 'Inter,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial'
    },
    dataLabels: {
      enabled: true,
      formatter: function(val){
        if (val == null) return '';
        const v = Number(val);
        const shown = v > 100 ? (v - 100) : v; // for merged mode, 100..200 => Available (shown as 0..100)
        const out = Math.round(shown * 10) / 10;
        return (out % 1 === 0 ? out.toFixed(0) : out.toFixed(1)) + '%';
      },
      style: { fontSize: '13px', fontWeight: 700 }
    },
    xaxis: { type: 'category', categories: X_CATEGORIES, labels: { rotate: -12, style: { fontSize:'13px', fontWeight:700 } } },
    yaxis: { labels: { style: { fontSize:'13px', fontWeight: 800 } } },
    plotOptions: { heatmap: { shadeIntensity: 0.2, radius: 5, useFillColorAsStroke: true, colorScale: { inverse: false, ranges: [] } } },
    legend: { show: false },
    tooltip: {
      y: {
        formatter: function(val, { seriesIndex, dataPointIndex, w }) {
          const d = (w.config.series[seriesIndex] && w.config.series[seriesIndex].data[dataPointIndex]) || {};
          const raw = Number(val);
          const kind = raw > 100 ? 'Available' : 'Booked';
          const shown = raw > 100 ? raw - 100 : raw;
          const days = (d.days !== undefined && d.total !== undefined) ? ` (${(d.days)}/${d.total} days)` : '';
          const out = Math.round(shown * 10) / 10;
          return `${kind}: ${(out % 1 === 0 ? out.toFixed(0) : out.toFixed(1))}%` + days;
        }
      }
    },
    series: []
  };

  // Color scales
  const BOOKED_RANGES = [
    { from: 0.0,  to: 0.1, color: '#FDEDED' },
    { from: 0.1,  to: 25,  color: '#FBC8C9' },
    { from: 25,   to: 50,  color: '#F79DA0' },
    { from: 50,   to: 75,  color: '#F16B71' },
    { from: 75,   to: 100, color: '#EF4444' }
  ];
  const VACANT_RANGES = [
    { from: 0.0,  to: 0.1, color: '#ECFDF5' },
    { from: 0.1,  to: 25,  color: '#D1FAE5' },
    { from: 25,   to: 50,  color: '#A7F3D0' },
    { from: 50,   to: 75,  color: '#6EE7B7' },
    { from: 75,   to: 100, color: '#10B981' }
  ];
  const BOTH_MERGED_RANGES = [
    { from: 0.0,   to: 0.1,  color: '#FDEDED' },
    { from: 0.1,   to: 25,   color: '#FBC8C9' },
    { from: 25,    to: 50,   color: '#F79DA0' },
    { from: 50,    to: 75,   color: '#F16B71' },
    { from: 75,    to: 100,  color: '#EF4444' },
    { from: 100.1, to: 125,  color: '#D1FAE5' },
    { from: 125,   to: 150,  color: '#A7F3D0' },
    { from: 150,   to: 175,  color: '#6EE7B7' },
    { from: 175,   to: 200,  color: '#10B981' }
  ];

  // Single-chart instance
  let currentMode = 'booked'; // 'booked' | 'vacant' | 'year-booked' | 'year-vacant' | 'year-both-merged' | 'year-both-split'
  const singleChartEl = document.querySelector("#heatmapSingle");
  let singleOptions = JSON.parse(JSON.stringify(baseOptions));
  singleOptions.series = SERIES_BOOKED;
  singleOptions.plotOptions.heatmap.colorScale.ranges = BOOKED_RANGES;
  const chartSingle = new ApexCharts(singleChartEl, singleOptions);
  chartSingle.render();

  // Split charts (lazily created)
  let chartSplitBooked = null;
  let chartSplitVacant = null;
  const splitWrap   = document.getElementById('heatmapSplitWrap');
  const splitBooked = document.getElementById('heatmapSplitBooked');
  const splitVacant = document.getElementById('heatmapSplitVacant');

  function showSingle(){
    splitWrap.classList.remove('active');
    document.getElementById('heatmapSingle').style.display = '';
  }
  function showSplit(){
    document.getElementById('heatmapSingle').style.display = 'none';
    splitWrap.classList.add('active');
  }

  // Buttons
  const btnBooked         = document.getElementById('btnBooked');
  const btnVacant         = document.getElementById('btnVacant');
  const btnYearBooked     = document.getElementById('btnYearBooked');
  const btnYearVacant     = document.getElementById('btnYearVacant');
  const btnYearBoth       = document.getElementById('btnYearBoth');
  const btnYearBothSplit  = document.getElementById('btnYearBothSplit');
  const legendNote        = document.getElementById('legendNote');

  function setActive(btn){
    [btnBooked, btnVacant, btnYearBooked, btnYearVacant, btnYearBoth, btnYearBothSplit].forEach(b => b.classList.remove('active'));
    if (btn) btn.classList.add('active');
  }
  function setLegendBooked(){
    legendNote.innerHTML = `
      <span><span class="sw booked"></span> Higher % booked</span>
      <span class="note">Cell value = % of days in the month</span>
    `;
  }
  function setLegendVacant(){
    legendNote.innerHTML = `
      <span><span class="sw vacant"></span> Higher % available</span>
      <span class="note">Cell value = % of days in the month</span>
    `;
  }
  function setLegendBothMerged(){
    legendNote.innerHTML = `
      <span><span class="sw booked"></span> Booked rows (0–100)</span>
      <span><span class="sw vacant"></span> Available rows (100–200 ➜ shown as %)</span>
      <span class="note">Labels/tooltips show true %</span>
    `;
  }
  function setLegendBothSplit(){
    legendNote.innerHTML = `
      <span><span class="sw booked"></span> Year — Booked heatmap</span>
      <span><span class="sw vacant"></span> Year — Available heatmap</span>
      <span class="note">January → December side by side</span>
    `;
  }

  // Window Booked
  btnBooked.addEventListener('click', () => {
    if (currentMode === 'booked') return;
    currentMode = 'booked';
    showSingle();
    setActive(btnBooked);
    setLegendBooked();
    chartSingle.updateOptions({
      xaxis: { categories: X_CATEGORIES },
      plotOptions: { heatmap: { colorScale: { ranges: BOOKED_RANGES } } },
      series: SERIES_BOOKED,
      chart: { height: Math.max(380, (SERIES_BOOKED.length * 32) + 160) }
    }, true, true);
  });

  // Window Available
  btnVacant.addEventListener('click', () => {
    if (currentMode === 'vacant') return;
    currentMode = 'vacant';
    showSingle();
    setActive(btnVacant);
    setLegendVacant();
    chartSingle.updateOptions({
      xaxis: { categories: X_CATEGORIES },
      plotOptions: { heatmap: { colorScale: { ranges: VACANT_RANGES } } },
      series: SERIES_VACANT,
      chart: { height: Math.max(380, (SERIES_VACANT.length * 32) + 160) }
    }, true, true);
  });

  // Year – Booked
  btnYearBooked.addEventListener('click', () => {
    if (currentMode === 'year-booked') return;
    currentMode = 'year-booked';
    showSingle();
    setActive(btnYearBooked);
    setLegendBooked();
    chartSingle.updateOptions({
      xaxis: { categories: X_CATEGORIES_YEAR },
      plotOptions: { heatmap: { colorScale: { ranges: BOOKED_RANGES } } },
      series: SERIES_YEAR_BOOKED,
      chart: { height: Math.max(380, (SERIES_YEAR_BOOKED.length * 32) + 160) }
    }, true, true);
  });

  // Year – Available
  btnYearVacant.addEventListener('click', () => {
    if (currentMode === 'year-vacant') return;
    currentMode = 'year-vacant';
    showSingle();
    setActive(btnYearVacant);
    setLegendVacant();
    chartSingle.updateOptions({
      xaxis: { categories: X_CATEGORIES_YEAR },
      plotOptions: { heatmap: { colorScale: { ranges: VACANT_RANGES } } },
      series: SERIES_YEAR_VACANT,
      chart: { height: Math.max(380, (SERIES_YEAR_VACANT.length * 32) + 160) }
    }, true, true);
  });

  // Year – Both (Merged)
  btnYearBoth.addEventListener('click', () => {
    if (currentMode === 'year-both-merged') return;
    currentMode = 'year-both-merged';
    showSingle();
    setActive(btnYearBoth);
    setLegendBothMerged();
    const seriesMerged = SERIES_YEAR_BOTH_MERGED; // 2 rows per unit
    chartSingle.updateOptions({
      xaxis: { categories: X_CATEGORIES_YEAR },
      plotOptions: { heatmap: { colorScale: { ranges: BOTH_MERGED_RANGES } } },
      series: seriesMerged,
      chart: { height: Math.max(380, (seriesMerged.length * 28) + 180) }
    }, true, true);
  });

  // Year – Both (Side-by-side)
  btnYearBothSplit.addEventListener('click', () => {
    if (currentMode === 'year-both-split') return;
    currentMode = 'year-both-split';
    setActive(btnYearBothSplit);
    setLegendBothSplit();
    showSplit();

    const bookedHeight = Math.max(360, (SERIES_YEAR_BOOKED.length * 28) + 160);
    const vacantHeight = Math.max(360, (SERIES_YEAR_VACANT.length * 28) + 160);

    // Create/update Booked chart
    if (!chartSplitBooked) {
      const optsB = JSON.parse(JSON.stringify(baseOptions));
      optsB.xaxis.categories = X_CATEGORIES_YEAR;
      optsB.plotOptions.heatmap.colorScale.ranges = BOOKED_RANGES;
      optsB.series = SERIES_YEAR_BOOKED;
      optsB.chart.height = bookedHeight;
      chartSplitBooked = new ApexCharts(splitBooked, optsB);
      chartSplitBooked.render();
    } else {
      chartSplitBooked.updateOptions({
        xaxis: { categories: X_CATEGORIES_YEAR },
        plotOptions: { heatmap: { colorScale: { ranges: BOOKED_RANGES } } },
        series: SERIES_YEAR_BOOKED,
        chart: { height: bookedHeight }
      }, true, true);
    }

    // Create/update Available chart
    if (!chartSplitVacant) {
      const optsV = JSON.parse(JSON.stringify(baseOptions));
      optsV.xaxis.categories = X_CATEGORIES_YEAR;
      optsV.plotOptions.heatmap.colorScale.ranges = VACANT_RANGES;
      optsV.series = SERIES_YEAR_VACANT;
      optsV.chart.height = vacantHeight;
      chartSplitVacant = new ApexCharts(splitVacant, optsV);
      chartSplitVacant.render();
    } else {
      chartSplitVacant.updateOptions({
        xaxis: { categories: X_CATEGORIES_YEAR },
        plotOptions: { heatmap: { colorScale: { ranges: VACANT_RANGES } } },
        series: SERIES_YEAR_VACANT,
        chart: { height: vacantHeight }
      }, true, true);
    }
  });

  // ====== Detailed Dates: toggle Window / Year ======
  const btnDatesWindow = document.getElementById('btnDatesWindow');
  const btnDatesYear   = document.getElementById('btnDatesYear');

  function toggleTableDates(mode){ // 'window' | 'year'
    const winEls  = document.querySelectorAll('.pills-window');
    const yearEls = document.querySelectorAll('.pills-year');
    if (mode === 'window') {
      winEls.forEach(el => el.style.display = '');
      yearEls.forEach(el => el.style.display = 'none');
    } else {
      winEls.forEach(el => el.style.display = 'none');
      yearEls.forEach(el => el.style.display = '');
    }
  }
  function setDatesActive(btn){
    [btnDatesWindow, btnDatesYear].forEach(b => b.classList.remove('active'));
    btn.classList.add('active');
  }

  btnDatesWindow.addEventListener('click', () => { setDatesActive(btnDatesWindow); toggleTableDates('window'); });
  btnDatesYear.addEventListener('click',   () => { setDatesActive(btnDatesYear);   toggleTableDates('year');   });

  // ====== Pills "Show more / less" ======
  document.addEventListener('click', function(e){
    if (e.target && e.target.classList.contains('pill-toggle')) {
      const cell = e.target.closest('.cell-pills');
      const expanded = cell.getAttribute('data-collapsed') === '0';
      if (expanded) {
        cell.setAttribute('data-collapsed','1');
        const extraCount = cell.querySelectorAll('.pill.extra').length;
        e.target.textContent = '+' + extraCount + ' more';
        e.target.setAttribute('aria-expanded','false');
      } else {
        cell.setAttribute('data-collapsed','0');
        e.target.textContent = 'Show less';
        e.target.setAttribute('aria-expanded','true');
      }
    }
  });

  // ====== Default mode (if caller passed &mode=year-...) ======
  window.addEventListener('DOMContentLoaded', () => {
    const m = (DEFAULT_MODE || '').toLowerCase();
    if (m === 'year-both-split') { btnYearBothSplit.click(); }
    else if (m === 'year-both')  { btnYearBoth.click(); }
    else if (m === 'year-booked'){ btnYearBooked.click(); }
    else if (m === 'year-vacant'){ btnYearVacant.click(); }
    // else leave default on "Booked" (window view)
  });
</script>

</body>
</html>
