document.addEventListener('DOMContentLoaded', function () {
  var state = {
    period: '7d',
    workspaceId: null,
    usage: null,
    derived: {
      localizedOperations: [],
      normalizedTimeline: [],
      timelineMaxValue: 0,
      totalCalls: 0,
    },
    loading: false,
    loadError: '',
  };

  var periodSelect = document.getElementById('period');
  var exportBtn = document.querySelector('.page-header-actions .btn-secondary');
  var chartWrap = document.getElementById('chart-bars');
  var tableBody = document.getElementById('usage-tbody');
  var chartTemplate = document.getElementById('tmpl-chart-bar');
  var rowTemplate = document.getElementById('tmpl-usage-row');
  var subtitle = document.querySelector('.section-card-subtitle');
  var statCards = document.querySelectorAll('.stats-grid .stat-card');

  function tKey(key) {
    return window.t ? t(key) : key;
  }

  function tfKey(key, vars) {
    return window.tf ? tf(key, vars) : tKey(key);
  }

  function currentLocale() {
    return localStorage.getItem('crank_lang') === 'ru' ? 'ru-RU' : 'en-US';
  }

  function currentWorkspaceId() {
    var workspace = window.getCurrentWorkspace ? window.getCurrentWorkspace() : null;
    return workspace ? workspace.id : null;
  }

  function element(tag, className, text) {
    var node = document.createElement(tag);
    if (className) node.className = className;
    if (text !== undefined && text !== null) node.textContent = text;
    return node;
  }

  function formatCount(value) {
    return Number(value || 0).toLocaleString(currentLocale());
  }

  function formatMs(value) {
    if (!value) {
      return '0ms';
    }
    if (value >= 1000) {
      return (value / 1000).toFixed(1) + 's';
    }
    return value + 'ms';
  }

  function periodLabel(period) {
    return tKey('usage.period.label.' + period);
  }

  function protocolColor(protocol) {
    if (protocol === 'graphql' || protocol === 'Graphql') {
      return 'var(--purple)';
    }
    if (protocol === 'grpc' || protocol === 'Grpc') {
      return 'var(--accent)';
    }
    if (protocol === 'websocket' || protocol === 'Websocket') {
      return 'var(--teal)';
    }
    if (protocol === 'soap' || protocol === 'Soap') {
      return 'var(--blue)';
    }
    return 'var(--blue)';
  }

  function protocolLabel(protocol) {
    if (protocol === 'graphql' || protocol === 'Graphql') {
      return 'GraphQL';
    }
    if (protocol === 'grpc' || protocol === 'Grpc') {
      return 'gRPC';
    }
    if (protocol === 'websocket' || protocol === 'Websocket') {
      return 'WebSocket';
    }
    if (protocol === 'soap' || protocol === 'Soap') {
      return 'SOAP';
    }
    return 'REST';
  }

  function localizedUsageOperation(operation) {
    if (!window.localizeDemoOperation) {
      return operation;
    }

    return window.localizeDemoOperation({
      name: operation.operation_name,
      operation_display_name: operation.operation_display_name,
      description: operation.operation_description || null,
    });
  }

  function chartBucketLabel(timestamp, period, index) {
    var date = new Date(timestamp);
    if (period === '7d') {
      return date.toLocaleDateString(currentLocale(), { weekday: 'short' });
    }
    if (period === '90d') {
      return date.toLocaleDateString(currentLocale(), { month: 'short' });
    }
    return tfKey('usage.chart.week', { index: index + 1 });
  }

  function toUtcBucketStart(date, period) {
    var bucket = new Date(date.getTime());
    bucket.setUTCMilliseconds(0);
    bucket.setUTCSeconds(0);
    bucket.setUTCMinutes(0);
    bucket.setUTCHours(0);

    if (period === '30d' || period === 'this_month') {
      var day = bucket.getUTCDay();
      var offset = day === 0 ? 6 : (day - 1);
      bucket.setUTCDate(bucket.getUTCDate() - offset);
      return bucket;
    }

    if (period === '90d') {
      bucket.setUTCDate(1);
      return bucket;
    }

    return bucket;
  }

  function shiftUtcBucket(date, period, amount) {
    var shifted = new Date(date.getTime());
    if (period === '30d' || period === 'this_month') {
      shifted.setUTCDate(shifted.getUTCDate() + (amount * 7));
      return shifted;
    }
    if (period === '90d') {
      shifted.setUTCMonth(shifted.getUTCMonth() + amount);
      return shifted;
    }
    shifted.setUTCDate(shifted.getUTCDate() + amount);
    return shifted;
  }

  function bucketKey(date) {
    return date.toISOString().slice(0, 19) + 'Z';
  }

  function expectedBucketCount(period, endBucket) {
    if (period === '7d') {
      return 7;
    }
    if (period === '30d') {
      return 5;
    }
    if (period === '90d') {
      return 4;
    }
    if (period === 'this_month') {
      var firstDay = new Date(Date.UTC(endBucket.getUTCFullYear(), endBucket.getUTCMonth(), 1));
      var firstWeek = toUtcBucketStart(firstDay, period);
      var diffMs = endBucket.getTime() - firstWeek.getTime();
      return Math.max(1, Math.floor(diffMs / (7 * 24 * 60 * 60 * 1000)) + 1);
    }
    return 7;
  }

  function normalizeTimeline(timeline, period) {
    if (!timeline.length) {
      return [];
    }

    var byBucket = {};
    timeline.forEach(function(point) {
      byBucket[point.bucket_start] = point;
    });

    var latestBucket = timeline.reduce(function(current, point) {
      return point.bucket_start > current.bucket_start ? point : current;
    }, timeline[0]);
    var endBucket = toUtcBucketStart(new Date(latestBucket.bucket_start), period);
    var bucketCount = expectedBucketCount(period, endBucket);
    var startBucket = shiftUtcBucket(endBucket, period, -(bucketCount - 1));
    var normalized = [];

    for (var index = 0; index < bucketCount; index += 1) {
      var bucketDate = shiftUtcBucket(startBucket, period, index);
      var key = bucketKey(bucketDate);
      normalized.push(byBucket[key] || {
        bucket_start: key,
        calls_ok: 0,
        calls_error: 0,
      });
    }

    return normalized;
  }

  function recomputeDerivedState() {
    var operations = state.usage ? (state.usage.operations || []) : [];
    var timeline = state.usage ? normalizeTimeline(state.usage.timeline || [], state.period) : [];
    var totalCalls = operations.reduce(function (sum, operation) {
      return sum + operation.calls_total;
    }, 0);
    var timelineMaxValue = timeline.reduce(function (maxValue, point) {
      return Math.max(maxValue, point.calls_ok + point.calls_error);
    }, 0);

    state.derived = {
      localizedOperations: operations.map(function (operation) {
        return {
          operation: operation,
          localized: localizedUsageOperation(operation),
        };
      }),
      normalizedTimeline: timeline,
      timelineMaxValue: timelineMaxValue,
      totalCalls: totalCalls,
    };
  }

  function buildEmptyState(title, message, compact) {
    var empty = element('div', 'empty-state');
    if (compact) {
      empty.style.padding = '0';
    }
    empty.appendChild(element('div', 'empty-state-title', title));
    empty.appendChild(element('div', 'empty-state-text', message));
    return empty;
  }

  function renderEmpty(title, message) {
    chartWrap.innerHTML = '';
    var chartEmpty = buildEmptyState(title, message, false);
    chartEmpty.style.width = '100%';
    chartWrap.appendChild(chartEmpty);

    tableBody.innerHTML = '';
    var row = document.createElement('tr');
    var cell = document.createElement('td');
    cell.colSpan = 7;
    cell.style.padding = '24px';
    cell.appendChild(buildEmptyState(title, message, true));
    row.appendChild(cell);
    tableBody.appendChild(row);
  }

  function renderStats() {
    var summary = state.usage ? state.usage.summary : null;
    var cards = [
      {
        value: formatCount(summary ? summary.rollup.calls_total : 0),
        text: tfKey('usage.stats.across', { period: periodLabel(state.period) }),
      },
      {
        value: ((summary ? summary.success_rate : 0) || 0).toFixed(1) + '%',
        text: tfKey('usage.stats.success_calls', { count: formatCount(summary ? summary.rollup.calls_ok : 0) }),
      },
      {
        value: formatMs(summary ? summary.rollup.p50_ms : 0),
        text: tKey('usage.stats.median'),
      },
      {
        value: formatMs(summary ? summary.rollup.p99_ms : 0),
        text: tfKey('usage.stats.error_calls', { count: formatCount(summary ? summary.rollup.calls_error : 0) }),
      }
    ];

    cards.forEach(function (card, index) {
      var node = statCards[index];
      if (!node) {
        return;
      }
      node.querySelector('.stat-value').textContent = card.value;
      var delta = node.querySelector('.stat-delta');
      delta.className = 'stat-delta';
      delta.textContent = card.text;
    });
  }

  function renderChart() {
    var timeline = state.derived.normalizedTimeline;
    chartWrap.innerHTML = '';

    if (!timeline.length) {
      var chartEmpty = buildEmptyState(
        tKey('usage.chart.empty.title'),
        tKey('usage.chart.empty.sub'),
        false
      );
      chartEmpty.style.width = '100%';
      chartWrap.appendChild(chartEmpty);
      return;
    }

    var maxValue = state.derived.timelineMaxValue;

    timeline.forEach(function (point, index) {
      var node = chartTemplate.content.cloneNode(true);
      var okHeight = maxValue ? Math.round((point.calls_ok / maxValue) * 160) : 0;
      var errorHeight = maxValue ? Math.round((point.calls_error / maxValue) * 160) : 0;
      if (point.calls_ok > 0) {
        okHeight = Math.max(okHeight, 6);
      }
      if (point.calls_error > 0) {
        errorHeight = Math.max(errorHeight, 6);
      }
      node.querySelector('.chart-bar.success').style.height = okHeight + 'px';
      node.querySelector('.chart-bar.success').dataset.tip = tfKey('usage.chart.ok', { count: formatCount(point.calls_ok) });
      node.querySelector('.chart-bar.error').style.height = errorHeight + 'px';
      node.querySelector('.chart-bar.error').dataset.tip = tfKey('usage.chart.errors', { count: formatCount(point.calls_error) });
      node.querySelector('.chart-col-label').textContent = chartBucketLabel(point.bucket_start, state.period, index);
      chartWrap.appendChild(node);
    });
  }

  function renderTable() {
    var operations = state.derived.localizedOperations;
    tableBody.innerHTML = '';

    if (!operations.length) {
      var row = document.createElement('tr');
      var cell = document.createElement('td');
      cell.colSpan = 7;
      cell.style.padding = '24px';
      cell.appendChild(
        buildEmptyState(
          tKey('usage.table.empty.title'),
          tKey('usage.table.empty.sub'),
          true
        )
      );
      row.appendChild(cell);
      tableBody.appendChild(row);
      return;
    }

    operations.forEach(function (entry) {
      var operation = entry.operation;
      var localizedOperation = entry.localized;
      var node = rowTemplate.content.cloneNode(true);
      var errorRate = operation.calls_total === 0
        ? 0
        : ((operation.calls_error / operation.calls_total) * 100);
      var share = state.derived.totalCalls === 0
        ? 0
        : ((operation.calls_total / state.derived.totalCalls) * 100);

      node.querySelector('.col-name').textContent = localizedOperation.operation_display_name || operation.operation_display_name;
      node.querySelector('.col-op-slug').textContent = operation.operation_name;

      var proto = node.querySelector('.col-proto');
      proto.textContent = protocolLabel(operation.protocol);
      proto.style.color = protocolColor(operation.protocol);

      node.querySelector('.col-calls').textContent = formatCount(operation.calls_total);
      node.querySelector('.col-errors').textContent = formatCount(operation.calls_error);

      var errorRateEl = node.querySelector('.col-err-rate');
      errorRateEl.textContent = errorRate.toFixed(2) + '%';
      errorRateEl.style.color = errorRate > 5 ? 'var(--red)' : (errorRate > 1 ? 'var(--amber)' : 'var(--green)');

      var latencyText = node.querySelector('.col-latency-text');
      latencyText.textContent =
        formatMs(operation.p50_ms) + ' / ' + formatMs(operation.p95_ms) + ' / ' + formatMs(operation.p99_ms);

      var base = Math.max(operation.p99_ms, 1);
      node.querySelector('.latency-p50').style.width = Math.max(4, Math.round((operation.p50_ms / base) * 64)) + 'px';
      node.querySelector('.latency-p95').style.width = Math.max(4, Math.round(((operation.p95_ms - operation.p50_ms) / base) * 64)) + 'px';
      node.querySelector('.latency-p99').style.width = Math.max(4, Math.round(((operation.p99_ms - operation.p95_ms) / base) * 64)) + 'px';

      node.querySelector('.col-quota-label').textContent = tfKey('usage.table.share', { value: share.toFixed(1) });
      node.querySelector('.col-quota-fill').style.width = share.toFixed(1) + '%';

      tableBody.appendChild(node);
    });
  }

  function renderUsage() {
    if (state.loading && !state.usage) {
      renderEmpty(tKey('usage.loading.title'), tKey('usage.loading.sub'));
      return;
    }

    if (state.loadError) {
      renderEmpty(tKey('usage.error.title'), state.loadError);
      return;
    }

    renderStats();
    renderChart();
    renderTable();
    if (subtitle) {
      subtitle.textContent = tfKey('usage.table.subtitle', { period: periodLabel(state.period) });
    }
  }

  async function loadUsage() {
    if (!window.CrankApi) {
      state.loadError = tKey('usage.error.api');
      renderUsage();
      return;
    }

    state.workspaceId = currentWorkspaceId();
    if (!state.workspaceId) {
      state.loadError = tKey('usage.error.workspace');
      renderUsage();
      return;
    }

    state.loading = true;
    state.loadError = '';
    renderUsage();

    try {
      state.usage = await window.CrankApi.getUsageOverview(state.workspaceId, { period: state.period });
      recomputeDerivedState();
    } catch (error) {
      state.loadError = error.message || tKey('usage.error.load');
      state.usage = null;
      recomputeDerivedState();
    } finally {
      state.loading = false;
      renderUsage();
    }
  }

  function exportCsv() {
    if (!state.usage) {
      if (window.CrankUi) {
        window.CrankUi.info(tKey('usage.export.empty.body'), tKey('usage.export.empty.title'));
      }
      return;
    }

    var rows = [tKey('usage.csv.header')];
    state.usage.operations.forEach(function (operation) {
      var localizedOperation = localizedUsageOperation(operation);
      var errorRate = operation.calls_total === 0
        ? 0
        : ((operation.calls_error / operation.calls_total) * 100);
      rows.push([
        '"' + (localizedOperation.operation_display_name || operation.operation_display_name) + '"',
        '"' + protocolLabel(operation.protocol) + '"',
        operation.calls_total,
        operation.calls_error,
        errorRate.toFixed(2),
        operation.p50_ms,
        operation.p95_ms,
        operation.p99_ms,
      ].join(','));
    });

    var blob = new Blob([rows.join('\r\n')], { type: 'text/csv' });
    var url = URL.createObjectURL(blob);
    var link = document.createElement('a');
    link.href = url;
    link.download = 'crank-usage-' + state.period + '.csv';
    link.click();
    URL.revokeObjectURL(url);
    if (window.CrankUi) {
      window.CrankUi.success(tKey('usage.export.done.body'), tKey('usage.export.done.title'));
    }
  }

  if (periodSelect) {
    periodSelect.value = state.period;
    periodSelect.addEventListener('change', function () {
      state.period = this.value;
      loadUsage();
    });
  }

  if (exportBtn) {
    exportBtn.addEventListener('click', exportCsv);
  }

  window.addEventListener('crank:workspacechange', loadUsage);

  if (window.whenWorkspacesReady) {
    window.whenWorkspacesReady().finally(loadUsage);
  } else {
    loadUsage();
  }
});
