{% extends "ewoooc_base.html" %}

{% block title %}業績資料自動化{% endblock %}
{% block page_attrs %}data-page-group="monitor" data-page-id="auto-import"{% endblock %}

{% block extra_head %}
  <link rel="stylesheet" href="{{ url_for('static', filename='css/page-auto-import.css') }}">
  <link rel="stylesheet" href="{{ url_for('static', filename='css/page-auto-import-bem.css') }}">
{% endblock %}

{% block content %}
<div class="auto-import-page">
  <div class="container">
    <header class="ai-head">
      <span class="ai-head__icon" aria-hidden="true"><i class="fas fa-arrows-rotate"></i></span>
      <div class="ai-head__main">
        <h1 class="ai-head__title">業績資料自動化</h1>
        <p class="ai-head__subtitle" id="pageRuntimeSummary">正在讀取正式資料狀態</p>
      </div>
      <div class="ai-head__actions">
        <button class="ai-icon-button" type="button" onclick="loadAll()" title="重新整理" aria-label="重新整理">
          <i class="fas fa-rotate"></i>
        </button>
        <button class="btn btn-primary" type="button" id="runAutomationButton" onclick="runAutomation()">
          <i class="fas fa-play me-1" aria-hidden="true"></i>執行自動取得
        </button>
      </div>
    </header>

    <section class="ai-cockpit" aria-label="業績資料狀態">
      <div class="ai-metric">
        <span class="ai-metric__label">最新業績</span>
        <strong class="ai-metric__value" id="freshnessValue">--</strong>
        <span class="ai-metric__meta" id="freshnessMeta">讀取中</span>
      </div>
      <div class="ai-metric">
        <span class="ai-metric__label">決策狀態</span>
        <strong class="ai-metric__value" id="closureValue">--</strong>
        <span class="ai-metric__meta" id="closureMeta">讀取中</span>
      </div>
      <div class="ai-metric">
        <span class="ai-metric__label">來源覆蓋</span>
        <strong class="ai-metric__value" id="sourceCoverageValue">--</strong>
        <span class="ai-metric__meta" id="sourceCoverageMeta">讀取中</span>
      </div>
      <div class="ai-metric">
        <span class="ai-metric__label">最近執行</span>
        <strong class="ai-metric__value ai-metric__value--compact" id="lastRunValue">--</strong>
        <span class="ai-metric__meta" id="lastRunMeta">尚無 receipt</span>
      </div>
    </section>

    <div class="ai-inline-status" id="automationAlert" role="status" hidden></div>

    <section class="ai-section" aria-labelledby="sourcesTitle">
      <header class="ai-section__head">
        <div>
          <span class="ai-section__eyebrow">授權來源</span>
          <h2 class="ai-section__title" id="sourcesTitle">資料來源</h2>
        </div>
        <span class="ai-mode-badge"><i class="fas fa-shield-halved" aria-hidden="true"></i>自動安全執行</span>
      </header>

      <div class="ai-source-list" id="sourceList" aria-live="polite">
        <div class="ai-source-row ai-source-row--loading">正在讀取來源狀態</div>
      </div>

      <details class="ai-disclosure">
        <summary><i class="fab fa-google-drive" aria-hidden="true"></i>Drive 來源設定</summary>
        <div class="ai-disclosure__body">
          <div id="configAlert"></div>
          <div class="ai-form-grid">
            <div>
              <label class="ai-field__label" for="folderPath">資料夾路徑</label>
              <input type="text" class="ai-field__input form-control" id="folderPath" autocomplete="off">
            </div>
            <div>
              <label class="ai-field__label" for="filePattern">檔名模式</label>
              <input type="text" class="ai-field__input form-control" id="filePattern" autocomplete="off">
            </div>
          </div>
          <div class="ai-toolbar">
            <button class="btn btn-primary" type="button" onclick="saveConfig()"><i class="fas fa-floppy-disk me-1"></i>儲存</button>
            <button class="btn btn-secondary" type="button" onclick="testConnection()"><i class="fas fa-plug me-1"></i>測試</button>
            <button class="btn btn-secondary" type="button" onclick="listFiles()"><i class="fas fa-list me-1"></i>檔案</button>
          </div>
        </div>
      </details>
    </section>

    <section class="ai-section" aria-labelledby="jobsTitle">
      <header class="ai-section__head">
        <div>
          <span class="ai-section__eyebrow">驗證紀錄</span>
          <h2 class="ai-section__title" id="jobsTitle">匯入紀錄</h2>
        </div>
        <button class="ai-icon-button" type="button" onclick="resetStuckJobs()" title="重置逾時任務" aria-label="重置逾時任務">
          <i class="fas fa-clock-rotate-left"></i>
        </button>
      </header>

      <div id="jobsLoading" class="ai-loading" hidden>
        <div class="spinner-border ai-loading__spinner" role="status"><span class="visually-hidden">載入中</span></div>
      </div>
      <div id="jobsEmpty" class="ai-empty" hidden>
        <i class="fas fa-inbox ai-empty__icon" aria-hidden="true"></i>
        <p class="ai-empty__text">尚無匯入紀錄</p>
      </div>
      <div id="jobsTableContainer" class="table-responsive" hidden>
        <table class="ai-jobtable" id="jobsTable">
          <thead>
            <tr>
              <th>來源檔案</th>
              <th>狀態</th>
              <th>進度</th>
              <th>筆數</th>
              <th>完成時間</th>
              <th>驗證結果</th>
            </tr>
          </thead>
          <tbody id="jobsTableBody"></tbody>
        </table>
      </div>
    </section>
  </div>
</div>
{% endblock %}

{% block extra_scripts %}
<script>
  const SOURCE_LABELS = {
    google_drive: 'Google Drive',
    authorized_https: '授權 HTTPS',
    authorized_imap: '授權信箱',
    controlled_local_drop: '受控落地目錄'
  };

  function escapeHtml(value) {
    const node = document.createElement('div');
    node.textContent = String(value || '');
    return node.innerHTML;
  }

  function formatTime(value) {
    if (!value) return '--';
    return new Date(value).toLocaleString('zh-TW', {
      month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit'
    });
  }

  function setAlert(elementId, type, message) {
    const element = document.getElementById(elementId);
    element.className = `ai-inline-status ai-inline-status--${type}`;
    element.innerHTML = message;
    element.hidden = false;
  }

  function sourceStatusLabel(source, runtimeState) {
    const runtimeLabels = {
      imported: '已匯入',
      duplicate: '無需更新',
      candidate_found: '處理中',
      empty: '待新檔',
      failed: '重試中',
      not_ready: '修復中',
      not_probed: '待探測',
      ready: '可用',
      disabled: '未啟用'
    };
    if (runtimeState && runtimeLabels[runtimeState]) return runtimeLabels[runtimeState];
    if (source.ready) return '可用';
    if (!source.enabled) return '未啟用';
    return source.status === 'incomplete' ? '設定未完整' : source.status === 'path_missing' ? '路徑不存在' : '不可用';
  }

  function receiptStatusLabel(status) {
    return ({
      completed: '完成',
      completed_no_write: '無需更新',
      partial: '部分完成',
      blocked_with_safe_next_action: '等待來源',
      degraded_no_write: '來源異常',
      failed_rolled_back: '已回滾'
    })[status] || '已記錄';
  }

  function renderReadiness(payload) {
    const freshness = payload.freshness || {};
    const coverage = payload.asset_coverage || {};
    const receipt = payload.last_receipt || null;
    const reconciliation = payload.source_reconciliation || {};
    const runtimeSources = new Map((reconciliation.sources || []).map(source => [source.id, source]));
    const nextRetry = reconciliation.next_retry_at;
    const lag = freshness.data_lag_days;
    document.getElementById('freshnessValue').textContent = freshness.latest_sales_date || '無資料';
    document.getElementById('freshnessMeta').textContent = lag === null || lag === undefined ? '尚未建立基準' : lag === 0 ? '今天已更新' : `落後 ${lag} 天`;
    document.getElementById('closureValue').textContent = freshness.decision_ready ? '可決策' : '受阻';
    document.getElementById('closureValue').dataset.state = freshness.decision_ready ? 'ready' : 'blocked';
    document.getElementById('closureMeta').textContent = freshness.decision_ready
      ? '新鮮度守門通過'
      : nextRetry
        ? `已排程 ${formatTime(nextRetry)}`
        : '等待最新業績';
    document.getElementById('sourceCoverageValue').textContent = `${coverage.ready || 0}/${coverage.total || 0}`;
    document.getElementById('sourceCoverageMeta').textContent = reconciliation.single_source_dependency
      ? '僅 1 個來源可用'
      : `${coverage.percent || 0}% 來源可用`;
    document.getElementById('lastRunValue').textContent = receipt ? formatTime(receipt.completed_at) : '尚無執行';
    document.getElementById('lastRunMeta').textContent = receipt ? receiptStatusLabel(receipt.status) : '尚無執行紀錄';
    document.getElementById('pageRuntimeSummary').textContent = freshness.decision_ready
      ? '正式業績可供分析與決策'
      : `正式業績${lag === null || lag === undefined ? '尚未建立' : `已落後 ${lag} 天`}`;

    const list = document.getElementById('sourceList');
    list.innerHTML = (payload.sources || []).map(source => {
      const runtime = runtimeSources.get(source.id) || {};
      const state = runtime.runtime_state || (source.ready ? 'ready' : source.enabled ? 'not_ready' : 'disabled');
      return `
      <div class="ai-source-row">
        <span class="ai-source-row__indicator ai-source-row__indicator--${state === 'imported' || state === 'ready' ? 'ready' : state === 'disabled' ? 'disabled' : 'degraded'}" aria-hidden="true"></span>
        <span class="ai-source-row__name">${escapeHtml(SOURCE_LABELS[source.id] || source.id)}</span>
        <span class="ai-source-row__state">${escapeHtml(sourceStatusLabel(source, state))}</span>
      </div>
    `;
    }).join('');
  }

  async function loadReadiness() {
    try {
      const response = await fetch('/api/auto_import/readiness');
      const payload = await response.json();
      if (!response.ok || !payload.success) throw new Error(payload.message || '狀態讀取失敗');
      renderReadiness(payload);
    } catch (error) {
      document.getElementById('pageRuntimeSummary').textContent = '正式狀態暫時無法讀取';
      setAlert('automationAlert', 'danger', '<i class="fas fa-triangle-exclamation" aria-hidden="true"></i>狀態讀取失敗');
    }
  }

  async function runAutomation() {
    const button = document.getElementById('runAutomationButton');
    button.disabled = true;
    button.innerHTML = '<i class="fas fa-spinner fa-spin me-1" aria-hidden="true"></i>執行中';
    setAlert('automationAlert', 'info', '<i class="fas fa-arrows-rotate fa-spin" aria-hidden="true"></i>正在探測授權來源並執行交易式驗證');
    try {
      const response = await fetch('/api/auto_import/run', { method: 'POST' });
      const payload = await response.json();
      const type = payload.success ? 'success' : payload.status === 'blocked_with_safe_next_action' ? 'warning' : 'danger';
      setAlert('automationAlert', type, `<i class="fas fa-${payload.success ? 'circle-check' : 'circle-exclamation'}" aria-hidden="true"></i>${escapeHtml(payload.message)}`);
      await Promise.all([loadReadiness(), loadJobs()]);
    } catch (error) {
      setAlert('automationAlert', 'danger', '<i class="fas fa-triangle-exclamation" aria-hidden="true"></i>自動取得執行失敗');
    } finally {
      button.disabled = false;
      button.innerHTML = '<i class="fas fa-play me-1" aria-hidden="true"></i>執行自動取得';
    }
  }

  async function loadConfig() {
    try {
      const response = await fetch('/api/import_config');
      const payload = await response.json();
      if (payload.success) {
        document.getElementById('folderPath').value = payload.data.folder_path || '';
        document.getElementById('filePattern').value = payload.data.file_pattern || '';
      }
    } catch (error) {
      console.error('Drive config read failed', error);
    }
  }

  async function saveConfig() {
    try {
      const response = await fetch('/api/import_config', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          folder_path: document.getElementById('folderPath').value,
          file_pattern: document.getElementById('filePattern').value
        })
      });
      const payload = await response.json();
      setAlert('configAlert', payload.success ? 'success' : 'danger', escapeHtml(payload.message));
      if (payload.success) loadReadiness();
    } catch (error) {
      setAlert('configAlert', 'danger', '設定儲存失敗');
    }
  }

  async function testConnection() {
    try {
      const response = await fetch('/api/test_drive_connection', { method: 'POST' });
      const payload = await response.json();
      setAlert('configAlert', payload.success ? 'success' : 'danger', escapeHtml(payload.message));
      loadReadiness();
    } catch (error) {
      setAlert('configAlert', 'danger', 'Drive 測試失敗');
    }
  }

  async function listFiles() {
    try {
      const response = await fetch('/api/list_drive_files', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          folder_path: document.getElementById('folderPath').value,
          file_pattern: document.getElementById('filePattern').value
        })
      });
      const payload = await response.json();
      setAlert('configAlert', payload.success ? 'success' : 'danger', payload.success ? `待處理檔案 ${payload.count} 個` : escapeHtml(payload.message));
    } catch (error) {
      setAlert('configAlert', 'danger', 'Drive 檔案讀取失敗');
    }
  }

  function jobStatusText(status) {
    return ({ pending: '等待', downloading: '取得', importing: '驗證', completed: '完成', failed: '失敗' })[status] || status;
  }

  function jobResult(job) {
    if (job.status === 'completed') return '雙表已驗證';
    if (job.status === 'failed') return job.display_error_message || '正式資料未變更';
    return job.current_step || '執行中';
  }

  function renderJobs(jobs) {
    const body = document.getElementById('jobsTableBody');
    body.innerHTML = jobs.map(job => {
      const running = ['pending', 'downloading', 'importing'].includes(job.status);
      const progress = Math.max(0, Math.min(100, Number(job.progress_percent || 0)));
      return `
        <tr>
          <td><span class="ai-jobtable__file"><i class="fas fa-file-excel" aria-hidden="true"></i>${escapeHtml(job.drive_file_name || '未記錄檔名')}</span></td>
          <td><span class="ai-status ai-status--${escapeHtml(job.status)}">${escapeHtml(jobStatusText(job.status))}</span></td>
          <td>
            <div class="ai-progress"><div class="ai-progress__bar" style="width:${progress}%" role="progressbar" aria-valuenow="${progress}" aria-valuemin="0" aria-valuemax="100"></div></div>
            <span class="ai-progress__label">${Math.round(progress)}%</span>
          </td>
          <td><span class="ai-count ai-count--ok">${job.success_rows || 0}</span><span class="ai-count-separator">/</span><span class="ai-count ai-count--total">${job.total_rows || 0}</span></td>
          <td><span class="ai-jobtable__time">${formatTime(job.completed_at)}</span></td>
          <td class="ai-jobtable__error">${escapeHtml(jobResult(job))}${running ? `<button class="ai-row-action" onclick="failJob(${job.id})" title="取消任務" aria-label="取消任務"><i class="fas fa-xmark"></i></button>` : ''}</td>
        </tr>`;
    }).join('');
  }

  async function loadJobs() {
    const loading = document.getElementById('jobsLoading');
    const empty = document.getElementById('jobsEmpty');
    const table = document.getElementById('jobsTableContainer');
    loading.hidden = false;
    empty.hidden = true;
    table.hidden = true;
    try {
      const response = await fetch('/api/import_jobs?limit=20');
      const payload = await response.json();
      const jobs = payload.success ? payload.data : [];
      if (jobs.length) {
        renderJobs(jobs);
        table.hidden = false;
      } else {
        empty.hidden = false;
      }
    } catch (error) {
      empty.hidden = false;
    } finally {
      loading.hidden = true;
    }
  }

  async function resetStuckJobs() {
    const response = await fetch('/api/reset_stuck_jobs', { method: 'POST' });
    const payload = await response.json();
    setAlert('automationAlert', payload.success ? 'success' : 'danger', escapeHtml(payload.message));
    loadJobs();
  }

  async function failJob(jobId) {
    await fetch(`/api/import_jobs/${jobId}/fail`, { method: 'POST' });
    loadJobs();
  }

  async function loadAll() {
    await Promise.all([loadReadiness(), loadConfig(), loadJobs()]);
  }

  loadAll();
  setInterval(loadJobs, 10000);
  setInterval(loadReadiness, 30000);
</script>
{% endblock %}
