import { createClient } from '@supabase/supabase-js';
import type { Database } from './database.types';
import { logSecurityEvent, logError } from './logger';
import fs from 'fs/promises';
import path from 'path';

// Environment variables
const supabaseUrl = process.env.SUPABASE_URL || import.meta.env.SUPABASE_URL || 'https://zctjaivtfyfxokfaemek.supabase.co';
const supabaseServiceKey = process.env.SUPABASE_SERVICE_KEY || import.meta.env.SUPABASE_SERVICE_KEY || '';

// Firebase configuration
const FIREBASE_PROJECT_ID = process.env.FIREBASE_PROJECT_ID || 'black-canyon-tickets-bct';
const FIREBASE_API_KEY = process.env.FIREBASE_API_KEY || 'AIzaSyDpXpjfQcNO_Lz7OuzINzZJG6pQXFOOLxI';
const FIREBASE_ADMIN_EMAIL = process.env.FIREBASE_ADMIN_EMAIL || 'Tyler@touchofcarepcp.com';
const FIREBASE_ADMIN_PASSWORD = process.env.FIREBASE_ADMIN_PASSWORD || '^A@6qDIOah*qNf)^i)1tbqtY';

const LAST_SYNC_FILE = path.join(process.cwd(), 'logs', 'last_firebase_sync.txt');
const SCRAPER_ORGANIZATION_ID = process.env.SCRAPER_ORGANIZATION_ID || 'f47ac10b-58cc-4372-a567-0e02b2c3d479';
const BCT_VENUE_ID = 'b47ac10b-58cc-4372-a567-0e02b2c3d479'; // Black Canyon Tickets venue

// Create Supabase client with proper types
let supabase: ReturnType<typeof createClient<Database>> | null = null;

try {
  if (supabaseUrl && supabaseServiceKey) {
    supabase = createClient<Database>(supabaseUrl, supabaseServiceKey);
  }
} catch (error) {
  logError('Failed to initialize Supabase client for scraper', error);
}

interface FirebaseEvent {
  id: string;
  name: string;
  description: string;
  location: string;
  datetime: string;
  images?: string[];
  tickets: Array<{
    type: string;
    price: string;
  }>;
  createdAt: string;
  updateTime: string;
}

interface ProcessedEvent {
  firebaseId: string;
  title: string;
  description: string;
  venue: string;
  startTime: string;
  endTime?: string;
  imageUrl?: string;
  category: string;
  priceRange: string;
}

/**
 * Authenticate with Firebase and get an ID token
 */
async function authenticateFirebase(): Promise<string | null> {
  try {
    const response = await fetch(`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${FIREBASE_API_KEY}`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        email: FIREBASE_ADMIN_EMAIL,
        password: FIREBASE_ADMIN_PASSWORD,
        returnSecureToken: true,
      }),
    });

    if (!response.ok) {
      throw new Error(`Firebase auth failed: ${response.status} ${response.statusText}`);
    }

    const data = await response.json();
    return data.idToken;
  } catch (error) {
    logError('Firebase authentication failed', error);
    return null;
  }
}

/**
 * Fetch all events from Firebase Firestore
 */
async function fetchFirebaseEvents(idToken: string): Promise<FirebaseEvent[]> {
  try {
    const response = await fetch(
      `https://firestore.googleapis.com/v1/projects/${FIREBASE_PROJECT_ID}/databases/(default)/documents/events`,
      {
        headers: {
          'Authorization': `Bearer ${idToken}`,
        },
      }
    );

    if (!response.ok) {
      throw new Error(`Firebase events fetch failed: ${response.status} ${response.statusText}`);
    }

    const data = await response.json();
    
    if (!data.documents) {
      return [];
    }

    return data.documents.map((doc: any) => {
      const fields = doc.fields;
      const documentId = doc.name.split('/').pop();
      
      return {
        id: documentId,
        name: fields.name?.stringValue || '',
        description: fields.description?.stringValue || '',
        location: fields.location?.stringValue || '',
        datetime: fields.datetime?.stringValue || '',
        images: fields.images?.arrayValue?.values?.map((v: any) => v.stringValue) || [],
        tickets: fields.tickets?.arrayValue?.values?.map((v: any) => ({
          type: v.mapValue.fields.type?.stringValue || '',
          price: v.mapValue.fields.price?.stringValue || '0',
        })) || [],
        createdAt: fields.createdAt?.timestampValue || doc.createTime,
        updateTime: doc.updateTime,
      };
    });
  } catch (error) {
    logError('Failed to fetch Firebase events', error);
    return [];
  }
}

/**
 * Determine event category based on content
 */
function categorizeEvent(name: string, description: string): string {
  const content = (name + ' ' + description).toLowerCase();
  
  const categoryKeywords = {
    music: ['concert', 'band', 'music', 'guitar', 'song', 'album', 'tour', 'performance'],
    community: ['fair', 'festival', 'county', 'community', 'celebration', 'rodeo', 'carnival'],
    sports: ['rodeo', 'bull', 'riding', 'horse', 'competition', 'race', 'athletic'],
    arts: ['theater', 'theatre', 'art', 'dance', 'performance', 'show'],
    food: ['food', 'wine', 'tasting', 'dinner', 'culinary'],
    business: ['conference', 'meeting', 'workshop', 'seminar', 'networking'],
  };

  let bestCategory = 'community';
  let maxMatches = 0;

  for (const [category, keywords] of Object.entries(categoryKeywords)) {
    const matches = keywords.filter(keyword => content.includes(keyword)).length;
    if (matches > maxMatches) {
      maxMatches = matches;
      bestCategory = category;
    }
  }

  return bestCategory;
}

/**
 * Parse date from Firebase datetime string
 */
function parseEventDate(datetime: string): { startTime: string; endTime?: string } {
  try {
    // Handle various date formats
    let date: Date;
    
    if (datetime.includes('August')) {
      // Parse formats like "August 8, 2025" or "August 6-9, 2025"
      const year = datetime.match(/202\d/)?.[0] || new Date().getFullYear().toString();
      
      if (datetime.includes('-')) {
        // Range format like "August 6-9, 2025"
        const match = datetime.match(/(\w+)\s+(\d+)-(\d+),\s*(\d+)/);
        if (match) {
          const [, month, startDay, endDay, yr] = match;
          const startDate = new Date(`${month} ${startDay}, ${yr}`);
          const endDate = new Date(`${month} ${endDay}, ${yr}`);
          
          return {
            startTime: startDate.toISOString(),
            endTime: endDate.toISOString(),
          };
        }
      } else {
        // Single date format like "August 8, 2025"
        date = new Date(datetime);
        if (!isNaN(date.getTime())) {
          return {
            startTime: date.toISOString(),
          };
        }
      }
    }
    
    // Try direct date parsing
    date = new Date(datetime);
    if (!isNaN(date.getTime())) {
      return {
        startTime: date.toISOString(),
      };
    }
    
    // Default to future date if parsing fails
    const futureDate = new Date();
    futureDate.setDate(futureDate.getDate() + 30);
    return {
      startTime: futureDate.toISOString(),
    };
  } catch (error) {
    // Fallback to future date
    const futureDate = new Date();
    futureDate.setDate(futureDate.getDate() + 30);
    return {
      startTime: futureDate.toISOString(),
    };
  }
}

/**
 * Calculate price range from tickets
 */
function calculatePriceRange(tickets: Array<{ type: string; price: string }>): string {
  if (tickets.length === 0) {
    return 'Price TBA';
  }
  
  const prices = tickets
    .map(ticket => parseFloat(ticket.price))
    .filter(price => !isNaN(price))
    .sort((a, b) => a - b);
  
  if (prices.length === 0) {
    return 'Price TBA';
  }
  
  const min = prices[0];
  const max = prices[prices.length - 1];
  
  if (min === max) {
    return `$${min.toFixed(2)}`;
  }
  
  return `$${min.toFixed(2)} - $${max.toFixed(2)}`;
}

/**
 * Process Firebase event into our format
 */
function processFirebaseEvent(firebaseEvent: FirebaseEvent): ProcessedEvent {
  const { startTime, endTime } = parseEventDate(firebaseEvent.datetime);
  
  return {
    firebaseId: firebaseEvent.id,
    title: firebaseEvent.name,
    description: firebaseEvent.description.substring(0, 500), // Limit description length
    venue: firebaseEvent.location,
    startTime,
    endTime,
    imageUrl: firebaseEvent.images && firebaseEvent.images.length > 0 ? firebaseEvent.images[0] : undefined,
    category: categorizeEvent(firebaseEvent.name, firebaseEvent.description),
    priceRange: calculatePriceRange(firebaseEvent.tickets),
  };
}

/**
 * Load last sync timestamp
 */
async function loadLastSyncTime(): Promise<string | null> {
  try {
    return await fs.readFile(LAST_SYNC_FILE, 'utf-8');
  } catch (error) {
    return null;
  }
}

/**
 * Save last sync timestamp
 */
async function saveLastSyncTime(timestamp: string): Promise<void> {
  try {
    await fs.mkdir(path.dirname(LAST_SYNC_FILE), { recursive: true });
    await fs.writeFile(LAST_SYNC_FILE, timestamp);
  } catch (error) {
    logError('Failed to save last sync time', error);
  }
}

/**
 * Check if event already exists in our database
 */
async function eventExistsInDatabase(firebaseId: string): Promise<boolean> {
  if (!supabase) {
    console.log(`❌ No Supabase client for checking event ${firebaseId}`);
    return false;
  }
  
  try {
    // Check for events with this Firebase ID in the description
    const { data, error } = await supabase
      .from('events')
      .select('id, title, external_source')
      .eq('external_source', 'firebase')
      .eq('organization_id', SCRAPER_ORGANIZATION_ID)
      .ilike('description', `%firebase_id:${firebaseId}%`)
      .single();
    
    if (error) {
      console.log(`🔍 Event firebase-${firebaseId} not found in database: ${error.message}`);
      return false;
    }
    
    if (data) {
      console.log(`✅ Event ${firebaseId} already exists: ${data.title}`);
      return true;
    }
    
    return false;
  } catch (error) {
    console.log(`❌ Error checking event ${firebaseId}:`, error);
    return false;
  }
}

/**
 * Add Firebase event to our database
 */
async function addEventToDatabase(processedEvent: ProcessedEvent): Promise<boolean> {
  if (!supabase) {
    console.log('❌ Supabase client not available for adding Firebase event');
    logError('Supabase client not available for adding Firebase event');
    return false;
  }
  
  try {
    // Generate a proper UUID for the event ID (can't use string concatenation)
    const eventId = crypto.randomUUID();
    console.log(`💾 Attempting to insert event with ID: ${eventId} (Firebase ID: ${processedEvent.firebaseId})`);
    
    // Insert the new event as featured and public
    const { error } = await supabase
      .from('events')
      .insert({
        id: eventId,
        title: processedEvent.title,
        slug: `firebase-event-${processedEvent.firebaseId.toLowerCase()}`,
        description: `${processedEvent.description}\n\n[firebase_id:${processedEvent.firebaseId}]`, // Hidden identifier
        venue: processedEvent.venue,
        venue_id: BCT_VENUE_ID,
        start_time: processedEvent.startTime,
        end_time: processedEvent.endTime,
        image_url: processedEvent.imageUrl,
        category: processedEvent.category,
        is_featured: true,
        is_public: true,
        is_published: true,
        external_source: 'firebase',
        organization_id: SCRAPER_ORGANIZATION_ID,
        created_by: SCRAPER_ORGANIZATION_ID,
      });
    
    if (error) {
      console.log(`❌ Database insert failed for ${processedEvent.title}:`, error);
      logError('Failed to insert Firebase event into database', error);
      return false;
    }
    
    console.log(`✅ Added featured event: ${processedEvent.title} (${processedEvent.priceRange})`);
    return true;
    
  } catch (error) {
    console.log(`💥 Exception adding event ${processedEvent.title}:`, error);
    logError('Error adding Firebase event to database', error);
    return false;
  }
}

/**
 * Main Firebase scraper function
 */
export async function runFirebaseEventScraper(): Promise<{ success: boolean; message: string; newEvents?: ProcessedEvent[] }> {
  try {
    console.log('🔍 Starting Firebase event scraper...');
    
    // Authenticate with Firebase
    const idToken = await authenticateFirebase();
    if (!idToken) {
      return {
        success: false,
        message: 'Failed to authenticate with Firebase',
      };
    }
    
    console.log('✅ Authenticated with Firebase');
    
    // Ensure scraper organization exists
    try {
      const orgInitialized = await initializeScraperOrganization();
      if (!orgInitialized) {
        return {
          success: false,
          message: 'Failed to initialize Black Canyon Tickets organization',
          debug: { step: 'organization_init_failed' },
        };
      }
    } catch (orgError) {
      return {
        success: false,
        message: `Organization initialization error: ${orgError instanceof Error ? orgError.message : 'Unknown error'}`,
        debug: { step: 'organization_init_exception', error: orgError },
      };
    }
    console.log('✅ Black Canyon Tickets organization ready');
    
    // Fetch events from Firebase
    const firebaseEvents = await fetchFirebaseEvents(idToken);
    console.log(`📅 Found ${firebaseEvents.length} events in Firebase`);
    
    if (firebaseEvents.length === 0) {
      return {
        success: true,
        message: 'No events found in Firebase',
      };
    }
    
    // Process and filter new events
    const newEvents: ProcessedEvent[] = [];
    
    console.log('🔍 Processing Firebase events...');
    for (const firebaseEvent of firebaseEvents) {
      console.log(`📅 Processing: ${firebaseEvent.name} (ID: ${firebaseEvent.id})`);
      
      const exists = await eventExistsInDatabase(firebaseEvent.id);
      
      if (!exists) {
        console.log(`🆕 Adding new event: ${firebaseEvent.name}`);
        const processedEvent = processFirebaseEvent(firebaseEvent);
        const added = await addEventToDatabase(processedEvent);
        
        if (added) {
          newEvents.push(processedEvent);
          console.log(`✅ Successfully added: ${processedEvent.title}`);
        } else {
          console.log(`❌ Failed to add: ${firebaseEvent.name}`);
        }
      } else {
        console.log(`⏭️  Event already exists: ${firebaseEvent.name}`);
      }
    }
    
    // Save sync timestamp
    await saveLastSyncTime(new Date().toISOString());
    
    // Log successful sync
    logSecurityEvent({
      type: 'firebase_scraper_success',
      severity: 'info',
      details: {
        totalEvents: firebaseEvents.length,
        newEvents: newEvents.length,
        syncTime: new Date().toISOString(),
      },
    });
    
    const message = newEvents.length > 0
      ? `Successfully synced ${newEvents.length} new events from Firebase`
      : `All Firebase events are already synchronized (found ${firebaseEvents.length} events in Firebase)`;
    
    return {
      success: true,
      message,
      newEvents: newEvents.length > 0 ? newEvents : undefined,
      debug: {
        firebaseEventsCount: firebaseEvents.length,
        firebaseEventTitles: firebaseEvents.map(e => e.name),
        newEventsCount: newEvents.length,
        processedEvents: firebaseEvents.map(e => ({
          name: e.name,
          id: e.id,
          processed: true
        })),
      },
    };
    
  } catch (error) {
    logError('Firebase event scraper failed', error);
    
    logSecurityEvent({
      type: 'firebase_scraper_error',
      severity: 'high',
      details: { error: error instanceof Error ? error.message : 'Unknown error' },
    });
    
    return {
      success: false,
      message: 'Firebase event scraper encountered an error',
    };
  }
}

/**
 * Initialize scraper organization if it doesn't exist
 */
export async function initializeScraperOrganization(): Promise<boolean> {
  if (!supabase) {
    return false;
  }
  
  try {
    // Check if scraper organization exists
    console.log(`🔍 Checking for organization: ${SCRAPER_ORGANIZATION_ID}`);
    const { data: existingOrg, error: checkError } = await supabase
      .from('organizations')
      .select('id')
      .eq('id', SCRAPER_ORGANIZATION_ID)
      .single();
    
    if (existingOrg) {
      console.log('✅ Organization already exists');
      return true;
    }
    
    console.log('🆕 Creating new organization:', checkError?.message);
    
    // Create scraper organization
    const { error: orgError } = await supabase
      .from('organizations')
      .insert({
        id: SCRAPER_ORGANIZATION_ID,
        name: 'Black Canyon Tickets',
        logo: null,
        stripe_account_id: null,
      });
    
    if (orgError) {
      console.log('❌ Failed to create organization:', orgError);
      logError('Failed to create scraper organization', orgError);
      return false;
    }
    
    // Create scraper user
    const { error: userError } = await supabase
      .from('users')
      .insert({
        id: SCRAPER_ORGANIZATION_ID,
        email: 'scraper@blackcanyontickets.com',
        name: 'Black Canyon Tickets Event Manager',
        organization_id: SCRAPER_ORGANIZATION_ID,
      });
    
    if (userError) {
      console.log('❌ Failed to create user:', userError);
      logError('Failed to create scraper user', userError);
      return false;
    }
    
    console.log('✅ Initialized Firebase scraper organization and user');
    return true;
    
  } catch (error) {
    logError('Failed to initialize scraper organization', error);
    return false;
  }
}