window.appState = {
  currentData: null,
  originalData: null, // Store original unprocessed data
  outputFormat: 'json',
  tutorialDismissed: false,
};

// Export the functions that frontend.js needs to call
window.backendAPI = {
  fetchData,
  jsonToYAML,
  formatDuration,
  formatEpochTime,
  processTimestamps,
};

document.addEventListener('DOMContentLoaded', function () {
  // Backend-specific initialization
});

// Function to convert seconds to human readable duration
function formatDuration(seconds, isMilliseconds = false) {
  if (!seconds || isNaN(seconds)) return seconds;

  // Convert to number in case it's a string
  const totalSeconds =
    isMilliseconds ? parseFloat(seconds) / 1000 : parseFloat(seconds);

  // Calculate days, hours, minutes, seconds
  const days = Math.floor(totalSeconds / 86400);
  const hours = Math.floor((totalSeconds % 86400) / 3600);
  const minutes = Math.floor((totalSeconds % 3600) / 60);
  const remainingSeconds = Math.floor(totalSeconds % 60);

  return `${days} Days ${hours} Hours ${minutes} Minutes ${remainingSeconds} Seconds`;
}

// Function to convert epoch time to human-readable format
function formatEpochTime(epoch, timezone) {
  if (!epoch) return epoch;

  // Check if epoch is in milliseconds (13 digits) or seconds (10 digits)
  const epochNumber = parseInt(epoch);
  if (isNaN(epochNumber)) return epoch;

  // Convert to milliseconds if needed
  const epochMs =
    epochNumber.toString().length <= 10 ? epochNumber * 1000 : epochNumber;

  // Parse the timezone offset
  let offset = 0;
  if (timezone !== 'UTC') {
    const match = timezone.match(/GMT([+-])(\d+)(?::(\d+))?/);
    if (match) {
      const sign = match[1] === '+' ? 1 : -1;
      const hours = parseInt(match[2]);
      const minutes = match[3] ? parseInt(match[3]) : 0;
      offset = sign * (hours * 60 + minutes) * 60 * 1000;
    }
  }

  // Create a date object and adjust for timezone
  const date = new Date(epochMs + offset);

  // Format the date
  return date.toUTCString().replace('GMT', timezone);
}

// YAML conversion function
function jsonToYAML(json) {
  const INDENT_SIZE = 2;

  function formatValue(value, indentLevel = 0) {
    const indent = ' '.repeat(indentLevel);

    if (value === null) return 'null';
    if (value === undefined) return '';

    if (typeof value === 'string') {
      // Check if string needs quotes (contains special chars)
      if (
        /[:{}[\],&*#?|\-<>=!%@`]/.test(value) ||
        value === '' ||
        !isNaN(value)
      ) {
        return `"${value.replace(/"/g, '\\"')}"`;
      }
      return value;
    }

    if (typeof value === 'number' || typeof value === 'boolean') {
      return value.toString();
    }

    if (Array.isArray(value)) {
      if (value.length === 0) return '[]';
      let result = '';
      for (const item of value) {
        result += `\n${indent}- ${formatValue(
          item,
          indentLevel + INDENT_SIZE
        ).trimStart()}`;
      }
      return result;
    }

    if (typeof value === 'object') {
      if (Object.keys(value).length === 0) return '{}';
      let result = '';
      for (const [key, val] of Object.entries(value)) {
        const formattedValue = formatValue(val, indentLevel + INDENT_SIZE);
        // If the formatted value is a multi-line value (array or object), add a line break
        if (formattedValue.includes('\n')) {
          result += `\n${indent}${key}:${formattedValue}`;
        } else {
          result += `\n${indent}${key}: ${formattedValue}`;
        }
      }
      return result;
    }

    return String(value);
  }

  return formatValue(json, 0).substring(1); // Remove first newline
}

// Function to recursively process timestamps and durations in the data
function processTimestamps(
  data,
  timezone,
  keysToConvert = [
    'date',
    'dateAdded',
    'utcStartSeconds',
    'utcEndSeconds',
    'timestamp',
    'startTime',
    'endTime',
  ],
  durationKeys = [
    'time',
    'timePlayedTotal',
    'timePlayed',
    'avgLifeTime',
    'duration',
    'objTime',
  ]
) {
  if (!data || typeof data !== 'object') return data;

  if (Array.isArray(data)) {
    return data.map((item) =>
      processTimestamps(item, timezone, keysToConvert, durationKeys)
    );
  }

  const result = {};
  for (const [key, value] of Object.entries(data)) {
    if (keysToConvert.includes(key) && typeof value === 'number') {
      result[key] = formatEpochTime(value, timezone);
    } else if (
      durationKeys.includes(key) &&
      typeof value === 'number' &&
      document.getElementById('replaceKeysOption').checked
    ) {
      // Check if the key is 'duration' to know if it's in milliseconds
      const isMilliseconds = key === 'duration';
      result[key] = formatDuration(value, isMilliseconds);
    } else if (typeof value === 'object' && value !== null) {
      result[key] = processTimestamps(
        value,
        timezone,
        keysToConvert,
        durationKeys
      );
    } else {
      result[key] = value;
    }
  }

  return result;
}

// Common fetch function
async function fetchData(endpoint, requestData) {
  console.log(`[CLIENT] Request to ${endpoint} at ${new Date().toISOString()}`);
  console.log(
    `[CLIENT] Request data: ${JSON.stringify({
      ...requestData,
      ssoToken:
        requestData.ssoToken ?
          requestData.ssoToken.substring(0, 5) + '...'
        : 'none',
    })}`
  );

  const errorElement = document.getElementById('error');
  const loadingElement = document.getElementById('loading');
  const resultsElement = document.getElementById('results');

  // Reset display
  errorElement.textContent = '';
  resultsElement.style.display = 'none';
  loadingElement.style.display = 'block';

  // Hide tutorial if not already dismissed
  if (!window.appState.tutorialDismissed) {
    window.appState.tutorialDismissed = true;
    document.querySelectorAll('.tutorial').forEach((element) => {
      element.style.display = 'none';
    });
  }

  // Validate request data
  // if (!requestData.ssoToken) {
  //   window.uiAPI.displayError('SSO Token is required');
  //   loadingElement.style.display = 'none';
  //   return;
  // }

  try {
    // Set up the request with a timeout
    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout

    const response = await fetch(endpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(requestData),
      signal: controller.signal,
    });

    clearTimeout(timeoutId);

    // Handle non-JSON responses
    const contentType = response.headers.get('content-type');
    if (!contentType || !contentType.includes('application/json')) {
      throw new Error('Server returned non-JSON response');
    }

    const data = await response.json();
    console.log(`[CLIENT] Response received at ${new Date().toISOString()}`);
    console.log(`[CLIENT] Response status: ${response.status}`);
    console.log(
      `[CLIENT] Response size: ~${JSON.stringify(data).length / 1024} KB`
    );

    if (!response.ok) {
      throw new Error(
        data.error || data.message || `Error: ${response.status}`
      );
    }

    if (data.error) {
      window.uiAPI.displayError(data.error);
    } else if (data.status === 'error') {
      window.uiAPI.displayError(data.message || 'An error occurred');
    } else {
      // Store both original and current data
      window.appState.originalData = structuredClone(data);
      window.appState.currentData = data;
      window.uiAPI.displayResults(data);
    }
  } catch (error) {
    if (error.name === 'AbortError') {
      window.uiAPI.displayError('Request timed out. Please try again.');
    } else {
      window.uiAPI.displayError(
        `Error: ${error.message || 'An error occurred while fetching data.'}`
      );
      console.error('Fetch error:', error);
    }
  } finally {
    loadingElement.style.display = 'none';
  }
}
