import L from 'leaflet';
import type { AddressGroup, VisitOutcome } from '@/types/canvass';
import { VISIT_OUTCOME_COLORS } from '@/types/canvass';

// Outcome priority order for cluster color aggregation
// Higher priority outcomes take precedence when determining cluster color
const OUTCOME_PRIORITY: Record<VisitOutcome | 'UNVISITED', number> = {
  UNVISITED: 1, // Highest priority - if any address unvisited, show gray
  COME_BACK_LATER: 2,
  NOT_HOME: 3,
  SPOKE_WITH: 4,
  LEFT_LITERATURE: 5,
  REFUSED: 6,
  ALREADY_VOTED: 7,
  MOVED: 8, // Lowest priority
};

const UNVISITED_COLOR = '#95a5a6'; // Gray

// Cluster metadata cache to avoid repeated calculations
interface ClusterMetadata {
  totalAddresses: number;
  hasUnvisited: boolean;
  outcomeCounts: Record<VisitOutcome, number>;
  dominantColor: string;
}

/**
 * Creates cluster metadata from marker group with single pass computation.
 * Calculates total addresses, visit status, outcome counts, and dominant color.
 *
 * @param markers - Array of Leaflet markers in the cluster
 * @returns Cluster metadata with all computed values
 */
function computeClusterMetadata(markers: L.Marker[]): ClusterMetadata {
  let totalAddresses = 0;
  let hasUnvisited = false;
  const outcomeCounts: Record<VisitOutcome, number> = {
    NOT_HOME: 0,
    REFUSED: 0,
    MOVED: 0,
    ALREADY_VOTED: 0,
    SPOKE_WITH: 0,
    LEFT_LITERATURE: 0,
    COME_BACK_LATER: 0,
  };

  for (const marker of markers) {
    const group = (marker.options as any).addressGroup as AddressGroup | undefined;
    if (!group) continue;

    totalAddresses += group.addresses.length;

    for (const address of group.addresses) {
      if (!address.lastVisit) {
        hasUnvisited = true;
      } else {
        outcomeCounts[address.lastVisit.outcome]++;
      }
    }
  }

  // Calculate dominant color
  let dominantColor = UNVISITED_COLOR;
  if (hasUnvisited) {
    dominantColor = UNVISITED_COLOR;
  } else {
    let highestPriority = Infinity;
    for (const [outcome, count] of Object.entries(outcomeCounts)) {
      if (count > 0) {
        const priority = OUTCOME_PRIORITY[outcome as VisitOutcome];
        if (priority < highestPriority) {
          highestPriority = priority;
          dominantColor = VISIT_OUTCOME_COLORS[outcome as VisitOutcome];
        }
      }
    }
  }

  return { totalAddresses, hasUnvisited, outcomeCounts, dominantColor };
}

/**
 * Determines the dominant outcome color for a cluster of markers.
 * Priority: Unvisited > Come Back Later > Not Home > Spoke With > etc.
 *
 * @param markers - Array of Leaflet markers in the cluster
 * @returns Hex color code for the cluster icon
 */
export function getClusterColor(markers: L.Marker[]): string {
  // Compute once, return color
  const metadata = computeClusterMetadata(markers);
  return metadata.dominantColor;
}

/**
 * Creates a custom cluster icon showing total address count and dominant outcome color.
 *
 * @param cluster - Leaflet marker cluster group
 * @returns Custom DivIcon for the cluster
 */
export function createClusterIcon(cluster: any): L.DivIcon {
  const markers = cluster.getAllChildMarkers();

  // Single pass computation - calculates all metadata at once
  const metadata = computeClusterMetadata(markers);

  // Generate circular badge HTML
  const html = `
    <div style="
      width: 40px;
      height: 40px;
      border-radius: 50%;
      background-color: ${metadata.dominantColor};
      border: 2px solid white;
      display: flex;
      align-items: center;
      justify-content: center;
      box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
      font-weight: bold;
      font-size: 14px;
      color: white;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    ">
      ${metadata.totalAddresses}
    </div>
  `;

  return L.divIcon({
    html,
    className: 'marker-cluster-custom',
    iconSize: [40, 40],
  });
}

/**
 * Configuration for MarkerClusterGroup component.
 * Optimized for performance and UX with address canvassing.
 */
export const CLUSTER_CONFIG = {
  maxClusterRadius: 50, // 50px clustering radius
  disableClusteringAtZoom: 18, // Disable at street zoom level (buildings clearly visible)
  spiderfyOnMaxZoom: false, // Zoom to bounds instead of spider
  showCoverageOnHover: false, // No polygon on hover (reduces visual clutter)
  zoomToBoundsOnClick: true, // Click cluster → zoom in
  animate: true, // Smooth zoom/pan animations
  animateAddingMarkers: false, // Skip animation when adding bulk markers (performance)
  removeOutsideVisibleBounds: true, // Remove offscreen markers from DOM (memory optimization)
  chunkedLoading: true, // Load markers in chunks to prevent UI freeze
};
