import type { TransactionMatch, YNABCategory, APIResponse } from './types';

let currentSessionId: string | null = null;
let matches: TransactionMatch[] = [];
let categories: YNABCategory[] = [];

// Initialize date inputs with default values (last 30 days)
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - 30);

const startDateInput = document.getElementById('startDate') as HTMLInputElement;
const endDateInput = document.getElementById('endDate') as HTMLInputElement;
const useUnapprovedCheckbox = document.getElementById('useUnapproved') as HTMLInputElement;
const dateRangeSection = document.getElementById('dateRangeSection') as HTMLDivElement;

startDateInput.value = startDate.toISOString().split('T')[0];
endDateInput.value = endDate.toISOString().split('T')[0];

// Fetch categories on page load
fetchCategories();

// Event listeners
document.getElementById('fetchBtn')?.addEventListener('click', fetchMatches);
document.getElementById('approveBtn')?.addEventListener('click', approveMatches);

// Toggle date range visibility based on checkbox
useUnapprovedCheckbox.addEventListener('change', () => {
  if (useUnapprovedCheckbox.checked) {
    dateRangeSection.style.display = 'none';
  } else {
    dateRangeSection.style.display = 'block';
  }
});

async function fetchCategories() {
  try {
    const response = await fetch('/api/categories');
    const data: APIResponse<YNABCategory[]> = await response.json();

    if (data.success && data.data) {
      categories = data.data;
      console.log(`Loaded ${categories.length} categories`);
    }
  } catch (error) {
    console.error('Error fetching categories:', error);
  }
}

async function fetchMatches() {
  const useUnapproved = useUnapprovedCheckbox.checked;
  const startDate = (document.getElementById('startDate') as HTMLInputElement).value;
  const endDate = (document.getElementById('endDate') as HTMLInputElement).value;

  // Validate inputs
  if (!useUnapproved && (!startDate || !endDate)) {
    showError('Please select both start and end dates or use unapproved transactions');
    return;
  }

  // Show loading state
  showSection('loading');
  hideError();

  try {
    const body: any = { useUnapproved };
    if (!useUnapproved) {
      body.startDate = startDate;
      body.endDate = endDate;
    }

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

    const data: APIResponse<{ sessionId: string; stats: any }> = await response.json();

    if (!data.success) {
      throw new Error(data.error || 'Failed to fetch matches');
    }

    currentSessionId = data.data!.sessionId;

    // Display statistics
    displayStats(data.data!.stats);

    // Fetch the matches
    await loadMatches();

    // Show matches section
    showSection('matches');
  } catch (error) {
    showSection('error');
    showError(error instanceof Error ? error.message : 'An error occurred');
  }
}

async function loadMatches() {
  if (!currentSessionId) return;

  try {
    const response = await fetch(`/api/matches/${currentSessionId}`);
    const data: APIResponse<TransactionMatch[]> = await response.json();

    if (!data.success) {
      throw new Error(data.error || 'Failed to load matches');
    }

    matches = data.data!;
    displayMatches();
  } catch (error) {
    showError(error instanceof Error ? error.message : 'Failed to load matches');
  }
}

function displayStats(stats: any) {
  const statsContainer = document.getElementById('stats')!;
  statsContainer.innerHTML = `
    <div class="stat-card">
      <div class="stat-label">Total Transactions</div>
      <div class="stat-value">${stats.total}</div>
    </div>
    <div class="stat-card">
      <div class="stat-label">Matched</div>
      <div class="stat-value">${stats.matched}</div>
    </div>
    <div class="stat-card">
      <div class="stat-label">High Confidence</div>
      <div class="stat-value">${stats.highConfidence}</div>
    </div>
    <div class="stat-card">
      <div class="stat-label">Medium Confidence</div>
      <div class="stat-value">${stats.mediumConfidence}</div>
    </div>
    <div class="stat-card">
      <div class="stat-label">Low Confidence</div>
      <div class="stat-value">${stats.lowConfidence}</div>
    </div>
  `;
}

function displayMatches() {
  const matchesList = document.getElementById('matchesList')!;
  matchesList.innerHTML = '';

  matches.forEach((match, index) => {
    const card = createMatchCard(match, index);
    matchesList.appendChild(card);
  });
}

function createMatchCard(match: TransactionMatch, index: number): HTMLDivElement {
  const card = document.createElement('div');
  card.className = `match-card ${match.status === 'approved' ? 'status-approved' : ''} ${match.status === 'rejected' ? 'status-rejected' : ''} ${!match.amazonOrder ? 'no-match' : ''}`;

  const amount = Math.abs(match.ynabTransaction.amount / 1000);
  const confidenceClass =
    match.matchConfidence >= 0.8
      ? 'confidence-high'
      : match.matchConfidence >= 0.5
      ? 'confidence-medium'
      : 'confidence-low';

  const confidencePercent = Math.round(match.matchConfidence * 100);

  card.innerHTML = `
    <div class="match-header">
      <div class="match-info">
        <div class="match-date">${match.ynabTransaction.date} • ${match.ynabTransaction.account_name}</div>
        <div class="match-payee">${match.ynabTransaction.payee_name || 'Unknown Payee'}</div>
        <div class="match-amount">$${amount.toFixed(2)}</div>
        ${match.ynabTransaction.memo ? `<div style="font-size: 0.9rem; color: #64748b; margin-top: 5px;">${match.ynabTransaction.memo}</div>` : ''}
      </div>
      ${match.amazonOrder ? `<div class="confidence-badge ${confidenceClass}">${confidencePercent}% Match</div>` : '<div class="confidence-badge confidence-low">No Match</div>'}
    </div>

    ${match.amazonOrder ? `
      <div class="amazon-order">
        <div class="order-header">Amazon Order #${match.amazonOrder.orderId}</div>
        <div class="order-items">
          ${match.amazonOrder.items.map(item => `• ${item.title} (${item.quantity}x $${item.price.toFixed(2)})`).join('<br>')}
        </div>
        <div>Total: $${match.amazonOrder.total.toFixed(2)}</div>
        <a href="${match.amazonOrder.orderUrl}" target="_blank" class="order-link">View on Amazon →</a>
      </div>

      <div class="category-select">
        <label style="font-size: 0.9rem; margin-bottom: 8px; display: block; color: #334155;">
          <strong>Category:</strong> ${match.suggestedCategory ? '✨ AI Suggested' : 'Select manually'}
        </label>
        <select id="category-${index}">
          <option value="">-- No Category Change --</option>
          ${renderCategoryOptions(match.suggestedCategory?.id)}
        </select>
      </div>

      <div class="match-actions">
        <button class="btn-small btn-approve" onclick="updateMatchStatus(${index}, 'approved')">
          ${match.status === 'approved' ? '✓ Approved' : 'Approve'}
        </button>
        <button class="btn-small btn-reject" onclick="updateMatchStatus(${index}, 'rejected')">
          ${match.status === 'rejected' ? '✗ Rejected' : 'Reject'}
        </button>
      </div>
    ` : `
      <div style="color: #64748b; font-style: italic; margin-top: 10px;">
        No matching Amazon order found within the date and amount tolerance.
      </div>
    `}
  `;

  return card;
}

function renderCategoryOptions(suggestedId?: string): string {
  const grouped = new Map<string, YNABCategory[]>();

  categories.forEach((cat) => {
    if (!grouped.has(cat.category_group_name)) {
      grouped.set(cat.category_group_name, []);
    }
    grouped.get(cat.category_group_name)!.push(cat);
  });

  let html = '';
  grouped.forEach((cats, groupName) => {
    html += `<optgroup label="${groupName}">`;
    cats.forEach((cat) => {
      const selected = cat.id === suggestedId ? 'selected' : '';
      html += `<option value="${cat.id}" ${selected}>${cat.name}</option>`;
    });
    html += '</optgroup>';
  });

  return html;
}

(window as any).updateMatchStatus = async (index: number, status: 'approved' | 'rejected') => {
  if (!currentSessionId) return;

  // Get the selected category
  const categorySelect = document.getElementById(`category-${index}`) as HTMLSelectElement;
  const categoryId = categorySelect?.value || null;
  const suggestedCategory = categoryId
    ? categories.find((c) => c.id === categoryId) || null
    : null;

  try {
    const response = await fetch(`/api/matches/${currentSessionId}/${index}`, {
      method: 'PATCH',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ status, suggestedCategory }),
    });

    const data: APIResponse<TransactionMatch> = await response.json();

    if (data.success && data.data) {
      matches[index] = data.data;
      displayMatches();
    }
  } catch (error) {
    console.error('Error updating match status:', error);
    showError('Failed to update match status');
  }
};

async function approveMatches() {
  if (!currentSessionId) return;

  const approvedCount = matches.filter((m) => m.status === 'approved').length;

  if (approvedCount === 0) {
    showError('No matches approved. Please approve at least one match before applying.');
    return;
  }

  if (!confirm(`Apply ${approvedCount} approved match(es) to YNAB?`)) {
    return;
  }

  showSection('loading');

  try {
    const response = await fetch(`/api/approve-matches/${currentSessionId}`, {
      method: 'POST',
    });

    const data: APIResponse<any[]> = await response.json();

    if (!data.success) {
      throw new Error(data.error || 'Failed to apply matches');
    }

    const results = data.data!;
    const successCount = results.filter((r) => r.success).length;
    const failCount = results.length - successCount;

    alert(
      `Successfully updated ${successCount} transaction(s)!${
        failCount > 0 ? `\n${failCount} failed.` : ''
      }`
    );

    showSection('matches');
  } catch (error) {
    showSection('matches');
    showError(error instanceof Error ? error.message : 'Failed to apply matches');
  }
}

function showSection(section: 'loading' | 'error' | 'matches' | 'stats') {
  document.getElementById('loadingSection')!.style.display = section === 'loading' ? 'block' : 'none';
  document.getElementById('errorSection')!.style.display = section === 'error' ? 'block' : 'none';
  document.getElementById('matchesSection')!.style.display = section === 'matches' ? 'block' : 'none';
  document.getElementById('statsSection')!.style.display = section === 'stats' || section === 'matches' ? 'block' : 'none';
}

function showError(message: string) {
  const errorMessage = document.getElementById('errorMessage')!;
  errorMessage.textContent = message;
  document.getElementById('errorSection')!.style.display = 'block';
}

function hideError() {
  document.getElementById('errorSection')!.style.display = 'none';
}
