// js/managers/GridManager.js

import { eventBus } from '../core/EventBus.js';
import { calendarConfig } from '../core/CalendarConfig.js';
import { EventTypes } from '../types/EventTypes.js';
import { DateUtils } from '../utils/DateUtils.js';

/**
 * Manages the calendar grid structure
 */
export class GridManager {
  constructor() {
    this.container = null;
    this.timeAxis = null;
    this.weekHeader = null;
    this.timeGrid = null;
    this.dayColumns = null;
    this.currentWeek = null;
    
    this.init();
  }

  init() {
    this.findElements();
    this.subscribeToEvents();
  }

  findElements() {
    this.container = document.querySelector('swp-calendar-container');
    this.timeAxis = document.querySelector('swp-time-axis');
    this.weekHeader = document.querySelector('swp-calendar-header');
    this.timeGrid = document.querySelector('swp-time-grid');
    this.scrollableContent = document.querySelector('swp-scrollable-content');
  }

  subscribeToEvents() {
    // Re-render grid on config changes
    eventBus.on(EventTypes.CONFIG_UPDATE, (e) => {
      if (['dayStartHour', 'dayEndHour', 'hourHeight', 'view', 'weekDays'].includes(e.detail.key)) {
        this.render();
      }
    });

    // Re-render on view change
    eventBus.on(EventTypes.VIEW_CHANGE, () => {
      this.render();
    });

    // Re-render on period change
    eventBus.on(EventTypes.PERIOD_CHANGE, (e) => {
      this.currentWeek = e.detail.week;
      this.renderHeaders();
    });

    // Handle grid clicks
    this.setupGridInteractions();
  }

  /**
   * Render the complete grid structure
   */
  render() {
    this.renderTimeAxis();
    this.renderHeaders();
    this.renderGrid();
    this.renderGridLines();
    
    // Emit grid rendered event
    eventBus.emit(EventTypes.GRID_RENDERED);
  }

  /**
   * Render time axis (left side hours)
   */
  renderTimeAxis() {
    if (!this.timeAxis) return;

    const startHour = calendarConfig.get('dayStartHour');
    const endHour = calendarConfig.get('dayEndHour');
    
    this.timeAxis.innerHTML = '';
    
    for (let hour = startHour; hour <= endHour; hour++) {
      const marker = document.createElement('swp-hour-marker');
      marker.textContent = this.formatHour(hour);
      marker.dataset.hour = hour;
      this.timeAxis.appendChild(marker);
    }
  }

  /**
   * Render week headers
   */
  renderHeaders() {
    if (!this.weekHeader || !this.currentWeek) return;

    const view = calendarConfig.get('view');
    const weekDays = calendarConfig.get('weekDays');
    
    this.weekHeader.innerHTML = '';

    if (view === 'week') {
      const dates = this.getWeekDates(this.currentWeek);
      const daysToShow = dates.slice(0, weekDays);
      
      daysToShow.forEach((date, index) => {
        const header = document.createElement('swp-day-header');
        header.innerHTML = `
          <swp-day-name>${this.getDayName(date)}</swp-day-name>
          <swp-day-date>${date.getDate()}</swp-day-date>
        `;
        header.dataset.date = this.formatDate(date);
        header.dataset.dayIndex = index;
        
        // Mark today
        if (this.isToday(date)) {
          header.dataset.today = 'true';
        }
        
        this.weekHeader.appendChild(header);
      });
    }
  }

  /**
   * Render the main grid structure
   */
  renderGrid() {
    if (!this.timeGrid) return;

    // Clear existing columns
    let dayColumns = this.timeGrid.querySelector('swp-day-columns');
    if (!dayColumns) {
      dayColumns = document.createElement('swp-day-columns');
      this.timeGrid.appendChild(dayColumns);
    }
    
    dayColumns.innerHTML = '';
    
    const view = calendarConfig.get('view');
    const columnsCount = view === 'week' ? calendarConfig.get('weekDays') : 1;
    
    // Create columns
    for (let i = 0; i < columnsCount; i++) {
      const column = document.createElement('swp-day-column');
      column.dataset.columnIndex = i;
      
      if (this.currentWeek) {
        const dates = this.getWeekDates(this.currentWeek);
        if (dates[i]) {
          column.dataset.date = this.formatDate(dates[i]);
        }
      }
      
      // Add events container
      const eventsLayer = document.createElement('swp-events-layer');
      column.appendChild(eventsLayer);
      
      dayColumns.appendChild(column);
    }

    this.dayColumns = dayColumns;
    this.updateGridStyles();
  }

  /**
   * Render grid lines
   */
  renderGridLines() {
    let gridLines = this.timeGrid.querySelector('swp-grid-lines');
    if (!gridLines) {
      gridLines = document.createElement('swp-grid-lines');
      this.timeGrid.insertBefore(gridLines, this.timeGrid.firstChild);
    }

    const totalHours = calendarConfig.totalHours;
    const hourHeight = calendarConfig.get('hourHeight');
    
    // Set CSS variables
    this.timeGrid.style.setProperty('--total-hours', totalHours);
    this.timeGrid.style.setProperty('--hour-height', `${hourHeight}px`);
    
    // Grid lines are handled by CSS
  }

  /**
   * Update grid CSS variables
   */
  updateGridStyles() {
    const root = document.documentElement;
    const config = calendarConfig.getAll();
    
    // Set CSS variables
    root.style.setProperty('--hour-height', `${config.hourHeight}px`);
    root.style.setProperty('--minute-height', `${config.hourHeight / 60}px`);
    root.style.setProperty('--snap-interval', config.snapInterval);
    root.style.setProperty('--day-start-hour', config.dayStartHour);
    root.style.setProperty('--day-end-hour', config.dayEndHour);
    root.style.setProperty('--work-start-hour', config.workStartHour);
    root.style.setProperty('--work-end-hour', config.workEndHour);
    
    // Set grid height
    const totalHeight = calendarConfig.totalHours * config.hourHeight;
    if (this.timeGrid) {
      this.timeGrid.style.height = `${totalHeight}px`;
    }
  }

  /**
   * Setup grid interaction handlers
   */
  setupGridInteractions() {
    if (!this.timeGrid) return;

    // Click handler
    this.timeGrid.addEventListener('click', (e) => {
      // Ignore if clicking on an event
      if (e.target.closest('swp-event')) return;
      
      const column = e.target.closest('swp-day-column');
      if (!column) return;

      const position = this.getClickPosition(e, column);
      
      eventBus.emit(EventTypes.GRID_CLICK, {
        date: column.dataset.date,
        time: position.time,
        minutes: position.minutes,
        columnIndex: parseInt(column.dataset.columnIndex)
      });
    });

    // Double click handler
    this.timeGrid.addEventListener('dblclick', (e) => {
      // Ignore if clicking on an event
      if (e.target.closest('swp-event')) return;
      
      const column = e.target.closest('swp-day-column');
      if (!column) return;

      const position = this.getClickPosition(e, column);
      
      eventBus.emit(EventTypes.GRID_DBLCLICK, {
        date: column.dataset.date,
        time: position.time,
        minutes: position.minutes,
        columnIndex: parseInt(column.dataset.columnIndex)
      });
    });
  }

  /**
   * Get click position in grid
   */
  getClickPosition(event, column) {
    const rect = column.getBoundingClientRect();
    const y = event.clientY - rect.top + this.scrollableContent.scrollTop;
    
    const minuteHeight = calendarConfig.minuteHeight;
    const snapInterval = calendarConfig.get('snapInterval');
    const dayStartHour = calendarConfig.get('dayStartHour');
    
    // Calculate minutes from start of day
    let minutes = Math.floor(y / minuteHeight);
    
    // Snap to interval
    minutes = Math.round(minutes / snapInterval) * snapInterval;
    
    // Add day start offset
    const totalMinutes = (dayStartHour * 60) + minutes;
    
    return {
      minutes: totalMinutes,
      time: this.minutesToTime(totalMinutes),
      y: minutes * minuteHeight
    };
  }

  /**
   * Utility methods
   */
  
  formatHour(hour) {
    const period = hour >= 12 ? 'PM' : 'AM';
    const displayHour = hour > 12 ? hour - 12 : (hour === 0 ? 12 : hour);
    return `${displayHour} ${period}`;
  }

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

  getDayName(date) {
    const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
    return days[date.getDay()];
  }

  getWeekDates(weekStart) {
    const dates = [];
    for (let i = 0; i < 7; i++) {
      const date = new Date(weekStart);
      date.setDate(weekStart.getDate() + i);
      dates.push(date);
    }
    return dates;
  }

  isToday(date) {
    const today = new Date();
    return date.toDateString() === today.toDateString();
  }

  minutesToTime(totalMinutes) {
    const hours = Math.floor(totalMinutes / 60);
    const minutes = totalMinutes % 60;
    const period = hours >= 12 ? 'PM' : 'AM';
    const displayHour = hours > 12 ? hours - 12 : (hours === 0 ? 12 : hours);
    
    return `${displayHour}:${minutes.toString().padStart(2, '0')} ${period}`;
  }

  /**
   * Scroll to specific hour
   */
  scrollToHour(hour) {
    if (!this.scrollableContent) return;
    
    const hourHeight = calendarConfig.get('hourHeight');
    const dayStartHour = calendarConfig.get('dayStartHour');
    const scrollTop = (hour - dayStartHour) * hourHeight;
    
    this.scrollableContent.scrollTop = scrollTop;
  }
}