<?php
require_once 'cong.php';
session_start();

if (empty($_SESSION['password']) || $_SESSION['password'] != LOGIN_PASSWORD) {
    unset($_SESSION['password']);
    unset($_SESSION['check_result']);
    echo("<script language=javascript>alert('密码错误!');window.location='ip_check_edit.php'; </script>");
    exit;
}

$defaultFrom = date('Y-m-d', strtotime('-6 days'));
$defaultTo   = date('Y-m-d');
?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>日志数据分析</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="//cdn.staticfile.org/layui/2.9.2/css/layui.css" rel="stylesheet">
  <script src="//cdn.staticfile.org/Chart.js/4.4.1/chart.umd.min.js"></script>
  <style>
    :root {
      --log-primary: #16baaa;
      --log-primary-dark: #0e8d81;
      --log-bg: #f0f2f5;
      --log-card: #ffffff;
      --log-border: #e8ecf1;
      --log-text: #2c3e50;
      --log-muted: #8c98a4;
    }
    * { box-sizing: border-box; }
    body { margin: 0; background: var(--log-bg); color: var(--log-text); font-family: 'Segoe UI', system-ui, sans-serif; }
    .log-page { max-width: 1680px; margin: 0 auto; padding: 24px 28px 40px; }
    .log-page-header { display: flex; align-items: flex-start; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin-bottom: 20px; }
    .log-page-header h1 { margin: 0; font-size: 1.35rem; font-weight: 600; }
    .log-page-header p { margin: 4px 0 0; font-size: .85rem; color: var(--log-muted); }
    .log-nav { display: flex; gap: 8px; flex-wrap: wrap; }
    .log-nav a {
      display: inline-block; padding: 6px 14px; border-radius: 6px; font-size: .85rem;
      text-decoration: none; border: 1px solid var(--log-border); background: #fff; color: var(--log-text);
    }
    .log-nav a.active { background: var(--log-primary); color: #fff; border-color: var(--log-primary); }
    .log-card {
      background: var(--log-card); border: 1px solid var(--log-border); border-radius: 10px;
      box-shadow: 0 2px 12px rgba(15, 23, 42, .04); margin-bottom: 16px; overflow: hidden;
    }
    .log-card-title { padding: 14px 20px; font-weight: 600; border-bottom: 1px solid var(--log-border); background: #fafbfc; }
    .log-card-body { padding: 18px 20px; }
    .stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; }
    .stat-item {
      background: linear-gradient(135deg, #f8fafc 0%, #eef3f9 100%);
      border: 1px solid var(--log-border); border-radius: 8px; padding: 14px 16px; text-align: center;
    }
    .stat-item .val { font-size: 1.5rem; font-weight: 700; color: var(--log-primary-dark); }
    .stat-item .lbl { font-size: .78rem; color: var(--log-muted); margin-top: 4px; }
    .chart-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
    .chart-box { position: relative; height: 280px; }
    .chart-box-wide { grid-column: 1 / -1; height: 300px; }
    .conclusion-list { margin: 0; padding: 0; list-style: none; }
    .conclusion-list li {
      padding: 10px 14px; margin-bottom: 8px; border-radius: 8px; font-size: .9rem; line-height: 1.5;
      background: #f0faf9; border-left: 3px solid var(--log-primary);
    }
    .conclusion-list li.alert { background: #fff8e6; border-left-color: #e6a23c; }
    .notice-bar {
      padding: 10px 16px; margin-bottom: 16px; border-radius: 8px; font-size: .85rem;
      background: #e8f4fd; color: #0c5460; border: 1px solid #bee5eb;
    }
    .loading-mask { text-align: center; padding: 60px; color: var(--log-muted); }
    @media (max-width: 900px) { .chart-grid { grid-template-columns: 1fr; } .chart-box-wide { grid-column: auto; } }
  </style>
</head>
<body>
<div class="log-page">
  <div class="log-page-header">
    <div>
      <h1>日志数据分析</h1>
      <p>判定结果、理由、国家与时序分布 · 自动分析结论</p>
    </div>
    <div class="log-nav">
      <a href="table.php">访问日志</a>
      <a href="log_analytics.php" class="active">数据分析</a>
      <a href="dashboard.php" target="_blank">配置中心</a>
    </div>
  </div>

  <div class="notice-bar">数据来源于 visitor_logs 表；若已开启异步写入，日志可能有短暂延迟（取决于队列 Worker 落库进度）。</div>

  <div class="log-card">
    <div class="log-card-body">
      <form class="layui-form layui-row layui-col-space16" id="filter-form">
        <div class="layui-col-md3">
          <input type="text" name="date_from" id="date_from" placeholder="开始日期" class="layui-input" value="<?php echo htmlspecialchars($defaultFrom); ?>">
        </div>
        <div class="layui-col-md3">
          <input type="text" name="date_to" id="date_to" placeholder="结束日期" class="layui-input" value="<?php echo htmlspecialchars($defaultTo); ?>">
        </div>
        <div class="layui-col-md3">
          <input type="text" name="domain" placeholder="域名（可选）" class="layui-input">
        </div>
        <div class="layui-col-md3">
          <input type="text" name="campagin_id" placeholder="策略 ID（可选）" class="layui-input">
        </div>
        <div class="layui-col-md12" style="margin-top:8px;">
          <button type="button" class="layui-btn" id="btn-query" style="background:var(--log-primary);">查询分析</button>
        </div>
      </form>
    </div>
  </div>

  <div id="content-area">
    <div class="loading-mask">加载中…</div>
  </div>
</div>

<script src="//cdn.staticfile.org/layui/2.9.2/layui.js"></script>
<script>
layui.use(['laydate'], function(){
  var laydate = layui.laydate;
  laydate.render({ elem: '#date_from', type: 'date' });
  laydate.render({ elem: '#date_to', type: 'date' });

  var charts = [];

  function destroyCharts() {
    charts.forEach(function(c){ try { c.destroy(); } catch(e){} });
    charts = [];
  }

  function renderStats(summary) {
    return '<div class="log-card"><div class="log-card-title">概览</div><div class="log-card-body"><div class="stat-grid">' +
      statBox(summary.total, '总访问') +
      statBox(summary.pass, '通过') +
      statBox(summary.block, '拦截') +
      statBox(summary.wait, '检测中') +
      statBox(summary.pass_rate + '%', '通过率') +
      statBox(summary.block_rate + '%', '拦截率') +
      '</div></div></div>';
  }

  function statBox(val, lbl) {
    return '<div class="stat-item"><div class="val">' + val + '</div><div class="lbl">' + lbl + '</div></div>';
  }

  function renderConclusions(list) {
    var html = '<div class="log-card"><div class="log-card-title">分析结论</div><div class="log-card-body"><ul class="conclusion-list">';
    (list || []).forEach(function(line) {
      var cls = (line.indexOf('告警') !== -1 || line.indexOf('关注') !== -1) ? 'alert' : '';
      html += '<li class="' + cls + '">' + escapeHtml(line) + '</li>';
    });
    html += '</ul></div></div>';
    return html;
  }

  function escapeHtml(s) {
    var d = document.createElement('div');
    d.textContent = s;
    return d.innerHTML;
  }

  function renderChartArea(data) {
    var hasTiming = data.timing && data.timing.stages && data.timing.stages.length > 0;
    return '<div class="log-card"><div class="log-card-title">可视化图表</div><div class="log-card-body chart-grid">' +
      '<div class="chart-box"><canvas id="chart-result"></canvas></div>' +
      '<div class="chart-box"><canvas id="chart-country"></canvas></div>' +
      '<div class="chart-box chart-box-wide"><canvas id="chart-hour"></canvas></div>' +
      '<div class="chart-box chart-box-wide"><canvas id="chart-reason"></canvas></div>' +
      (hasTiming ? '<div class="chart-box chart-box-wide"><canvas id="chart-timing"></canvas></div>' : '') +
      '</div></div>';
  }

  function makeChart(id, config) {
    var el = document.getElementById(id);
    if (!el) return;
    charts.push(new Chart(el, config));
  }

  function buildCharts(data) {
    var colors = ['#16baaa','#e74c3c','#f39c12','#3498db','#9b59b6','#1abc9c','#95a5a6'];

    if (data.by_result && data.by_result.length) {
      makeChart('chart-result', {
        type: 'doughnut',
        data: {
          labels: data.by_result.map(function(r){ return r.label; }),
          datasets: [{ data: data.by_result.map(function(r){ return r.count; }), backgroundColor: colors }]
        },
        options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: '判定结果分布' } } }
      });
    }

    if (data.by_country && data.by_country.length) {
      makeChart('chart-country', {
        type: 'bar',
        data: {
          labels: data.by_country.map(function(r){ return r.country; }),
          datasets: [{ label: '访问量', data: data.by_country.map(function(r){ return r.count; }), backgroundColor: '#16baaa' }]
        },
        options: { responsive: true, maintainAspectRatio: false, indexAxis: 'y', plugins: { title: { display: true, text: '国家 Top10' } } }
      });
    }

    if (data.by_hour && data.by_hour.length) {
      makeChart('chart-hour', {
        type: 'line',
        data: {
          labels: data.by_hour.map(function(r){ return r.hour; }),
          datasets: [{ label: '访问量', data: data.by_hour.map(function(r){ return r.count; }), borderColor: '#3498db', backgroundColor: 'rgba(52,152,219,.1)', fill: true, tension: 0.3 }]
        },
        options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: '24 小时访问分布' } } }
      });
    }

    if (data.by_reason && data.by_reason.length) {
      makeChart('chart-reason', {
        type: 'bar',
        data: {
          labels: data.by_reason.map(function(r){ return r.reason.length > 24 ? r.reason.slice(0,24)+'…' : r.reason; }),
          datasets: [{ label: '次数', data: data.by_reason.map(function(r){ return r.count; }), backgroundColor: '#e74c3c' }]
        },
        options: {
          responsive: true, maintainAspectRatio: false, indexAxis: 'y',
          plugins: { title: { display: true, text: '拦截/待判定理由 Top15' }, tooltip: { callbacks: { title: function(items){ return data.by_reason[items[0].dataIndex].reason; } } } }
        }
      });
    }

    if (data.timing && data.timing.stages && data.timing.stages.length) {
      var topStages = data.timing.stages.slice(0, 10);
      makeChart('chart-timing', {
        type: 'bar',
        data: {
          labels: topStages.map(function(s){ return s.stage; }),
          datasets: [{ label: '平均 ms', data: topStages.map(function(s){ return s.avg_ms; }), backgroundColor: '#9b59b6' }]
        },
        options: { responsive: true, maintainAspectRatio: false, plugins: { title: { display: true, text: '判定阶段平均耗时（抽样 ' + data.timing.sample_size + ' 条）' } } }
      });
    }
  }

  function loadData() {
    var form = document.getElementById('filter-form');
    var params = new URLSearchParams(new FormData(form));
    destroyCharts();
    document.getElementById('content-area').innerHTML = '<div class="loading-mask">分析中…</div>';

    fetch('datatable/log_analytics.php?' + params.toString())
      .then(function(r){ return r.json(); })
      .then(function(res) {
        if (res.code !== 0) {
          document.getElementById('content-area').innerHTML = '<div class="log-card"><div class="log-card-body">' + escapeHtml(res.msg || '加载失败') + '</div></div>';
          return;
        }
        var data = res.data;
        document.getElementById('content-area').innerHTML =
          renderStats(data.summary) + renderConclusions(data.conclusions) + renderChartArea(data);
        buildCharts(data);
      })
      .catch(function(err) {
        document.getElementById('content-area').innerHTML = '<div class="log-card"><div class="log-card-body">请求失败：' + escapeHtml(String(err)) + '</div></div>';
      });
  }

  document.getElementById('btn-query').addEventListener('click', loadData);
  loadData();
});
</script>
</body>
</html>
