// js/managers/DataManager.js

import { eventBus } from '../core/EventBus.js';
import { EventTypes } from '../types/EventTypes.js';

/**
 * Manages data fetching and API communication
 * Currently uses mock data until backend is implemented
 */
export class DataManager {
  constructor() {
    this.baseUrl = '/api/events';
    this.useMockData = true; // Toggle this when backend is ready
    this.cache = new Map();
    
    this.init();
  }

  init() {
    this.subscribeToEvents();
  }

  subscribeToEvents() {
    // Listen for period changes to fetch new data
    eventBus.on(EventTypes.PERIOD_CHANGE, (e) => {
      this.fetchEventsForPeriod(e.detail);
    });

    // Listen for event updates
    eventBus.on(EventTypes.EVENT_UPDATE, (e) => {
      this.updateEvent(e.detail);
    });

    // Listen for event creation
    eventBus.on(EventTypes.EVENT_CREATE, (e) => {
      this.createEvent(e.detail);
    });

    // Listen for event deletion
    eventBus.on(EventTypes.EVENT_DELETE, (e) => {
      this.deleteEvent(e.detail.eventId);
    });
  }

  /**
   * Fetch events for a specific period
   * @param {Object} period - Contains start, end, view
   */
  async fetchEventsForPeriod(period) {
    const cacheKey = `${period.start}-${period.end}-${period.view}`;
    
    // Check cache first
    if (this.cache.has(cacheKey)) {
      const cachedData = this.cache.get(cacheKey);
      eventBus.emit(EventTypes.DATA_FETCH_SUCCESS, cachedData);
      return cachedData;
    }

    // Emit loading start
    eventBus.emit(EventTypes.DATA_FETCH_START, { period });

    try {
      let data;
      
      if (this.useMockData) {
        // Simulate network delay
        await this.delay(300);
        data = this.getMockData(period);
      } else {
        // Real API call
        const params = new URLSearchParams({
          start: period.start,
          end: period.end,
          view: period.view
        });
        
        const response = await fetch(`${this.baseUrl}?${params}`);
        if (!response.ok) throw new Error('Failed to fetch events');
        
        data = await response.json();
      }

      // Cache the data
      this.cache.set(cacheKey, data);

      // Emit success
      eventBus.emit(EventTypes.DATA_FETCH_SUCCESS, data);
      
      return data;
    } catch (error) {
      eventBus.emit(EventTypes.DATA_FETCH_ERROR, { error: error.message });
      throw error;
    }
  }

  /**
   * Create a new event
   */
  async createEvent(eventData) {
    eventBus.emit(EventTypes.DATA_SYNC_START, { action: 'create' });

    try {
      if (this.useMockData) {
        await this.delay(200);
        const newEvent = {
          id: `evt-${Date.now()}`,
          ...eventData,
          syncStatus: 'synced'
        };
        
        // Clear cache to force refresh
        this.cache.clear();
        
        eventBus.emit(EventTypes.DATA_SYNC_SUCCESS, { 
          action: 'create', 
          event: newEvent 
        });
        
        return newEvent;
      } else {
        // Real API call
        const response = await fetch(this.baseUrl, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(eventData)
        });
        
        if (!response.ok) throw new Error('Failed to create event');
        
        const newEvent = await response.json();
        this.cache.clear();
        
        eventBus.emit(EventTypes.DATA_SYNC_SUCCESS, { 
          action: 'create', 
          event: newEvent 
        });
        
        return newEvent;
      }
    } catch (error) {
      eventBus.emit(EventTypes.DATA_SYNC_ERROR, { 
        action: 'create', 
        error: error.message 
      });
      throw error;
    }
  }

  /**
   * Update an existing event
   */
  async updateEvent(updateData) {
    eventBus.emit(EventTypes.DATA_SYNC_START, { action: 'update' });

    try {
      if (this.useMockData) {
        await this.delay(200);
        
        // Clear cache to force refresh
        this.cache.clear();
        
        eventBus.emit(EventTypes.DATA_SYNC_SUCCESS, { 
          action: 'update', 
          eventId: updateData.eventId,
          changes: updateData.changes
        });
        
        return true;
      } else {
        // Real API call
        const response = await fetch(`${this.baseUrl}/${updateData.eventId}`, {
          method: 'PATCH',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(updateData.changes)
        });
        
        if (!response.ok) throw new Error('Failed to update event');
        
        this.cache.clear();
        
        eventBus.emit(EventTypes.DATA_SYNC_SUCCESS, { 
          action: 'update', 
          eventId: updateData.eventId 
        });
        
        return true;
      }
    } catch (error) {
      eventBus.emit(EventTypes.DATA_SYNC_ERROR, { 
        action: 'update', 
        error: error.message,
        eventId: updateData.eventId
      });
      throw error;
    }
  }

  /**
   * Delete an event
   */
  async deleteEvent(eventId) {
    eventBus.emit(EventTypes.DATA_SYNC_START, { action: 'delete' });

    try {
      if (this.useMockData) {
        await this.delay(200);
        
        // Clear cache to force refresh
        this.cache.clear();
        
        eventBus.emit(EventTypes.DATA_SYNC_SUCCESS, { 
          action: 'delete', 
          eventId 
        });
        
        return true;
      } else {
        // Real API call
        const response = await fetch(`${this.baseUrl}/${eventId}`, {
          method: 'DELETE'
        });
        
        if (!response.ok) throw new Error('Failed to delete event');
        
        this.cache.clear();
        
        eventBus.emit(EventTypes.DATA_SYNC_SUCCESS, { 
          action: 'delete', 
          eventId 
        });
        
        return true;
      }
    } catch (error) {
      eventBus.emit(EventTypes.DATA_SYNC_ERROR, { 
        action: 'delete', 
        error: error.message,
        eventId
      });
      throw error;
    }
  }

  /**
   * Generate mock data for testing
   */
  getMockData(period) {
    const events = [];
    const types = ['meeting', 'meal', 'work', 'milestone'];
    const titles = {
      meeting: ['Team Standup', 'Client Meeting', 'Project Review', 'Sprint Planning', 'Design Review'],
      meal: ['Breakfast', 'Lunch', 'Coffee Break', 'Dinner'],
      work: ['Deep Work Session', 'Code Review', 'Documentation', 'Testing'],
      milestone: ['Project Deadline', 'Release Day', 'Demo Day']
    };

    // Parse dates
    const startDate = new Date(period.start);
    const endDate = new Date(period.end);
    
    // Generate some events for each day
    for (let d = new Date(startDate); d <= endDate; d.setDate(d.getDate() + 1)) {
      // Skip weekends for most events
      const dayOfWeek = d.getDay();
      const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
      
      if (isWeekend) {
        // Maybe one or two events on weekends
        if (Math.random() > 0.7) {
          const type = 'meal';
          const title = titles[type][Math.floor(Math.random() * titles[type].length)];
          const hour = 12 + Math.floor(Math.random() * 4);
          
          events.push({
            id: `evt-${events.length + 1}`,
            title,
            type,
            start: `${this.formatDate(d)}T${hour}:00:00`,
            end: `${this.formatDate(d)}T${hour + 1}:00:00`,
            allDay: false,
            syncStatus: 'synced'
          });
        }
      } else {
        // Regular workday events
        
        // Morning standup
        if (Math.random() > 0.3) {
          events.push({
            id: `evt-${events.length + 1}`,
            title: 'Team Standup',
            type: 'meeting',
            start: `${this.formatDate(d)}T09:00:00`,
            end: `${this.formatDate(d)}T09:30:00`,
            allDay: false,
            syncStatus: 'synced'
          });
        }

        // Lunch
        events.push({
          id: `evt-${events.length + 1}`,
          title: 'Lunch',
          type: 'meal',
          start: `${this.formatDate(d)}T12:00:00`,
          end: `${this.formatDate(d)}T13:00:00`,
          allDay: false,
          syncStatus: 'synced'
        });

        // Random afternoon events
        const numAfternoonEvents = Math.floor(Math.random() * 3) + 1;
        for (let i = 0; i < numAfternoonEvents; i++) {
          const type = types[Math.floor(Math.random() * types.length)];
          const title = titles[type][Math.floor(Math.random() * titles[type].length)];
          const startHour = 13 + Math.floor(Math.random() * 4);
          const duration = 1 + Math.floor(Math.random() * 2);
          
          events.push({
            id: `evt-${events.length + 1}`,
            title,
            type,
            start: `${this.formatDate(d)}T${startHour}:${Math.random() > 0.5 ? '00' : '30'}:00`,
            end: `${this.formatDate(d)}T${startHour + duration}:00:00`,
            allDay: false,
            syncStatus: Math.random() > 0.9 ? 'pending' : 'synced'
          });
        }
      }
    }

    // Add a multi-day event
    if (period.view === 'week') {
      const midWeek = new Date(startDate);
      midWeek.setDate(midWeek.getDate() + 2);
      
      events.push({
        id: `evt-${events.length + 1}`,
        title: 'Project Sprint',
        type: 'milestone',
        start: `${this.formatDate(startDate)}T00:00:00`,
        end: `${this.formatDate(midWeek)}T23:59:59`,
        allDay: true,
        syncStatus: 'synced'
      });
    }

    return {
      events,
      meta: {
        start: period.start,
        end: period.end,
        view: period.view,
        total: events.length
      }
    };
  }

  /**
   * Utility methods
   */
  
  formatDate(date) {
    return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
  }

  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  /**
   * Clear all cached data
   */
  clearCache() {
    this.cache.clear();
  }

  /**
   * Toggle between mock and real data
   */
  setUseMockData(useMock) {
    this.useMockData = useMock;
    this.clearCache();
  }
}