import { 
  PopGridPosition, 
  GridMode, 
  GRID_BREAKPOINTS,
  GridBreakpoint,
  GapPreset,
  GAP_PRESETS,
  PopLayoutDataV5,
  PopComponentDefinitionV5, 
} from "../types/pop-layout";

// ========================================
// Gap/Padding 조정
// ========================================

/**
 * Gap 프리셋에 따라 breakpoint의 gap/padding 조정
 * 
 * @param base 기본 breakpoint 설정
 * @param preset Gap 프리셋 ("narrow" | "medium" | "wide")
 * @returns 조정된 breakpoint (gap, padding 계산됨)
 */
export function getAdjustedBreakpoint(
  base: GridBreakpoint,
  preset: GapPreset
): GridBreakpoint {
  const multiplier = GAP_PRESETS[preset]?.multiplier || 1.0;
  
  return {
    ...base,
    gap: Math.round(base.gap * multiplier),
    padding: Math.max(8, Math.round(base.padding * multiplier)), // 최소 8px
  };
}

// ========================================
// 그리드 위치 변환
// ========================================

/**
 * 12칸 기준 위치를 다른 모드로 변환
 */
export function convertPositionToMode(
  position: PopGridPosition,
  targetMode: GridMode
): PopGridPosition {
  const sourceColumns = 12;
  const targetColumns = GRID_BREAKPOINTS[targetMode].columns;
  
  // 같은 칸 수면 그대로 반환
  if (sourceColumns === targetColumns) {
    return position;
  }
  
  const ratio = targetColumns / sourceColumns;
  
  // 열 위치 변환
  let newCol = Math.max(1, Math.ceil((position.col - 1) * ratio) + 1);
  let newColSpan = Math.max(1, Math.round(position.colSpan * ratio));
  
  // 범위 초과 방지
  if (newCol > targetColumns) {
    newCol = 1;
  }
  if (newCol + newColSpan - 1 > targetColumns) {
    newColSpan = targetColumns - newCol + 1;
  }
  
  return {
    col: newCol,
    row: position.row,
    colSpan: Math.max(1, newColSpan),
    rowSpan: position.rowSpan,
  };
}

/**
 * 여러 컴포넌트를 모드별로 변환하고 겹침 해결
 * 
 * v5.1 자동 줄바꿈:
 * - 원본 col > targetColumns인 컴포넌트는 자동으로 맨 아래에 배치
 * - 정보 손실 방지: 모든 컴포넌트가 그리드 안에 배치됨
 */
export function convertAndResolvePositions(
  components: Array<{ id: string; position: PopGridPosition }>,
  targetMode: GridMode
): Array<{ id: string; position: PopGridPosition }> {
  // 엣지 케이스: 빈 배열
  if (components.length === 0) {
    return [];
  }
  
  const targetColumns = GRID_BREAKPOINTS[targetMode].columns;
  
  // 1단계: 각 컴포넌트를 비율로 변환 (원본 col 보존)
  const converted = components.map(comp => ({
    id: comp.id,
    position: convertPositionToMode(comp.position, targetMode),
    originalCol: comp.position.col, // 원본 col 보존
  }));
  
  // 2단계: 정상 컴포넌트 vs 초과 컴포넌트 분리
  const normalComponents = converted.filter(c => c.originalCol <= targetColumns);
  const overflowComponents = converted.filter(c => c.originalCol > targetColumns);
  
  // 3단계: 정상 컴포넌트의 최대 row 계산
  const maxRow = normalComponents.length > 0
    ? Math.max(...normalComponents.map(c => c.position.row + c.position.rowSpan - 1))
    : 0;
  
  // 4단계: 초과 컴포넌트들을 맨 아래에 순차 배치
  let currentRow = maxRow + 1;
  const wrappedComponents = overflowComponents.map(comp => {
    const wrappedPosition: PopGridPosition = {
      col: 1, // 왼쪽 끝부터 시작
      row: currentRow,
      colSpan: Math.min(comp.position.colSpan, targetColumns), // 최대 칸 수 제한
      rowSpan: comp.position.rowSpan,
    };
    currentRow += comp.position.rowSpan; // 다음 행으로 이동
    
    return {
      id: comp.id,
      position: wrappedPosition,
    };
  });
  
  // 5단계: 정상 + 줄바꿈 컴포넌트 병합
  const adjusted = [
    ...normalComponents.map(c => ({ id: c.id, position: c.position })),
    ...wrappedComponents,
  ];
  
  // 6단계: 겹침 해결 (아래로 밀기)
  return resolveOverlaps(adjusted, targetColumns);
}

// ========================================
// 검토 필요 판별
// ========================================

/**
 * 컴포넌트가 현재 모드에서 "검토 필요" 상태인지 확인
 * 
 * v5.1 검토 필요 기준:
 * - 12칸 모드(기본 모드)가 아님
 * - 해당 모드에서 오버라이드가 없음 (아직 편집 안 함)
 * 
 * @param currentMode 현재 그리드 모드
 * @param hasOverride 해당 모드에서 오버라이드 존재 여부
 * @returns true = 검토 필요, false = 검토 완료 또는 불필요
 */
export function needsReview(
  currentMode: GridMode,
  hasOverride: boolean
): boolean {
  const targetColumns = GRID_BREAKPOINTS[currentMode].columns;
  
  // 12칸 모드는 기본 모드이므로 검토 불필요
  if (targetColumns === 12) {
    return false;
  }
  
  // 오버라이드가 있으면 이미 편집함 → 검토 완료
  if (hasOverride) {
    return false;
  }
  
  // 오버라이드 없으면 → 검토 필요
  return true;
}

/**
 * @deprecated v5.1부터 needsReview() 사용 권장
 * 
 * 기존 isOutOfBounds는 "화면 밖" 개념이었으나,
 * v5.1 자동 줄바꿈으로 인해 모든 컴포넌트가 그리드 안에 배치됩니다.
 * 대신 needsReview()로 "검토 필요" 여부를 판별하세요.
 */
export function isOutOfBounds(
  originalPosition: PopGridPosition,
  currentMode: GridMode,
  overridePosition?: PopGridPosition | null
): boolean {
  const targetColumns = GRID_BREAKPOINTS[currentMode].columns;
  
  // 12칸 모드면 초과 불가
  if (targetColumns === 12) {
    return false;
  }
  
  // 오버라이드가 있으면 오버라이드 위치로 판단
  if (overridePosition) {
    return overridePosition.col > targetColumns;
  }
  
  // 오버라이드 없으면 원본 col로 판단
  return originalPosition.col > targetColumns;
}

// ========================================
// 겹침 감지 및 해결
// ========================================

/**
 * 두 위치가 겹치는지 확인
 */
export function isOverlapping(a: PopGridPosition, b: PopGridPosition): boolean {
  // 열 겹침 체크
  const aColEnd = a.col + a.colSpan - 1;
  const bColEnd = b.col + b.colSpan - 1;
  const colOverlap = !(aColEnd < b.col || bColEnd < a.col);
  
  // 행 겹침 체크
  const aRowEnd = a.row + a.rowSpan - 1;
  const bRowEnd = b.row + b.rowSpan - 1;
  const rowOverlap = !(aRowEnd < b.row || bRowEnd < a.row);
  
  return colOverlap && rowOverlap;
}

/**
 * 겹침 해결 (아래로 밀기)
 */
export function resolveOverlaps(
  positions: Array<{ id: string; position: PopGridPosition }>,
  columns: number
): Array<{ id: string; position: PopGridPosition }> {
  // row, col 순으로 정렬
  const sorted = [...positions].sort((a, b) => 
    a.position.row - b.position.row || a.position.col - b.position.col
  );
  
  const resolved: Array<{ id: string; position: PopGridPosition }> = [];
  
  sorted.forEach((item) => {
    let { row, col, colSpan, rowSpan } = item.position;
    
    // 열이 범위를 초과하면 조정
    if (col + colSpan - 1 > columns) {
      colSpan = columns - col + 1;
    }
    
    // 기존 배치와 겹치면 아래로 이동
    let attempts = 0;
    const maxAttempts = 100;
    
    while (attempts < maxAttempts) {
      const currentPos: PopGridPosition = { col, row, colSpan, rowSpan };
      const hasOverlap = resolved.some(r => isOverlapping(currentPos, r.position));
      
      if (!hasOverlap) break;
      
      row++;
      attempts++;
    }
    
    resolved.push({
      id: item.id,
      position: { col, row, colSpan, rowSpan },
    });
  });
  
  return resolved;
}

// ========================================
// 좌표 변환
// ========================================

/**
 * 마우스 좌표 → 그리드 좌표 변환
 * 
 * CSS Grid 계산 방식:
 * - 사용 가능 너비 = 캔버스 너비 - 패딩*2 - gap*(columns-1)
 * - 각 칸 너비 = 사용 가능 너비 / columns
 * - 셀 N의 시작 X = padding + (N-1) * (칸너비 + gap)
 */
export function mouseToGridPosition(
  mouseX: number,
  mouseY: number,
  canvasRect: DOMRect,
  columns: number,
  rowHeight: number,
  gap: number,
  padding: number
): { col: number; row: number } {
  // 캔버스 내 상대 위치 (패딩 영역 포함)
  const relX = mouseX - canvasRect.left - padding;
  const relY = mouseY - canvasRect.top - padding;
  
  // CSS Grid 1fr 계산과 동일하게
  // 사용 가능 너비 = 전체 너비 - 양쪽 패딩 - (칸 사이 gap)
  const availableWidth = canvasRect.width - padding * 2 - gap * (columns - 1);
  const colWidth = availableWidth / columns;
  
  // 각 셀의 실제 간격 (셀 너비 + gap)
  const cellStride = colWidth + gap;
  
  // 그리드 좌표 계산 (1부터 시작)
  // relX를 cellStride로 나누면 몇 번째 칸인지 알 수 있음
  const col = Math.max(1, Math.min(columns, Math.floor(relX / cellStride) + 1));
  const row = Math.max(1, Math.floor(relY / (rowHeight + gap)) + 1);
  
  return { col, row };
}

/**
 * 그리드 좌표 → 픽셀 좌표 변환
 */
export function gridToPixelPosition(
  col: number,
  row: number,
  colSpan: number,
  rowSpan: number,
  canvasWidth: number,
  columns: number,
  rowHeight: number,
  gap: number,
  padding: number
): { x: number; y: number; width: number; height: number } {
  const totalGap = gap * (columns - 1);
  const colWidth = (canvasWidth - padding * 2 - totalGap) / columns;
  
  return {
    x: padding + (col - 1) * (colWidth + gap),
    y: padding + (row - 1) * (rowHeight + gap),
    width: colWidth * colSpan + gap * (colSpan - 1),
    height: rowHeight * rowSpan + gap * (rowSpan - 1),
  };
}

// ========================================
// 위치 검증
// ========================================

/**
 * 위치가 그리드 범위 내에 있는지 확인
 */
export function isValidPosition(
  position: PopGridPosition,
  columns: number
): boolean {
  return (
    position.col >= 1 &&
    position.row >= 1 &&
    position.colSpan >= 1 &&
    position.rowSpan >= 1 &&
    position.col + position.colSpan - 1 <= columns
  );
}

/**
 * 위치를 그리드 범위 내로 조정
 */
export function clampPosition(
  position: PopGridPosition,
  columns: number
): PopGridPosition {
  let { col, row, colSpan, rowSpan } = position;
  
  // 최소값 보장
  col = Math.max(1, col);
  row = Math.max(1, row);
  colSpan = Math.max(1, colSpan);
  rowSpan = Math.max(1, rowSpan);
  
  // 열 범위 초과 방지
  if (col + colSpan - 1 > columns) {
    if (col > columns) {
      col = 1;
    }
    colSpan = columns - col + 1;
  }
  
  return { col, row, colSpan, rowSpan };
}

// ========================================
// 자동 배치
// ========================================

/**
 * 다음 빈 위치 찾기
 */
export function findNextEmptyPosition(
  existingPositions: PopGridPosition[],
  colSpan: number,
  rowSpan: number,
  columns: number
): PopGridPosition {
  let row = 1;
  let col = 1;
  
  const maxAttempts = 1000;
  let attempts = 0;
  
  while (attempts < maxAttempts) {
    const candidatePos: PopGridPosition = { col, row, colSpan, rowSpan };
    
    // 범위 체크
    if (col + colSpan - 1 > columns) {
      col = 1;
      row++;
      continue;
    }
    
    // 겹침 체크
    const hasOverlap = existingPositions.some(pos => 
      isOverlapping(candidatePos, pos)
    );
    
    if (!hasOverlap) {
      return candidatePos;
    }
    
    // 다음 위치로 이동
    col++;
    if (col + colSpan - 1 > columns) {
      col = 1;
      row++;
    }
    
    attempts++;
  }
  
  // 실패 시 마지막 행에 배치
  return { col: 1, row: row + 1, colSpan, rowSpan };
}

/**
 * 컴포넌트들을 자동으로 배치
 */
export function autoLayoutComponents(
  components: Array<{ id: string; colSpan: number; rowSpan: number }>,
  columns: number
): Array<{ id: string; position: PopGridPosition }> {
  const result: Array<{ id: string; position: PopGridPosition }> = [];
  
  let currentRow = 1;
  let currentCol = 1;
  
  components.forEach(comp => {
    // 현재 행에 공간이 부족하면 다음 행으로
    if (currentCol + comp.colSpan - 1 > columns) {
      currentRow++;
      currentCol = 1;
    }
    
    result.push({
      id: comp.id,
      position: {
        col: currentCol,
        row: currentRow,
        colSpan: comp.colSpan,
        rowSpan: comp.rowSpan,
      },
    });
    
    currentCol += comp.colSpan;
  });
  
  return result;
}

// ========================================
// 유효 위치 계산 (통합 함수)
// ========================================

/**
 * 컴포넌트의 유효 위치를 계산합니다.
 * 우선순위: 1. 오버라이드 → 2. 자동 재배치 → 3. 원본 위치
 * 
 * @param componentId 컴포넌트 ID
 * @param layout 전체 레이아웃 데이터
 * @param mode 현재 그리드 모드
 * @param autoResolvedPositions 미리 계산된 자동 재배치 위치 (선택적)
 */
export function getEffectiveComponentPosition(
  componentId: string,
  layout: PopLayoutDataV5,
  mode: GridMode,
  autoResolvedPositions?: Array<{ id: string; position: PopGridPosition }>
): PopGridPosition | null {
  const component = layout.components[componentId];
  if (!component) return null;
  
  // 1순위: 오버라이드가 있으면 사용
  const override = layout.overrides?.[mode]?.positions?.[componentId];
  if (override) {
    return { ...component.position, ...override };
  }
  
  // 2순위: 자동 재배치된 위치 사용
  if (autoResolvedPositions) {
    const autoResolved = autoResolvedPositions.find(p => p.id === componentId);
    if (autoResolved) {
      return autoResolved.position;
    }
  } else {
    // 자동 재배치 직접 계산
    const componentsArray = Object.entries(layout.components).map(([id, comp]) => ({
      id,
      position: comp.position,
    }));
    const resolved = convertAndResolvePositions(componentsArray, mode);
    const autoResolved = resolved.find(p => p.id === componentId);
    if (autoResolved) {
      return autoResolved.position;
    }
  }
  
  // 3순위: 원본 위치 (12칸 모드)
  return component.position;
}

/**
 * 모든 컴포넌트의 유효 위치를 일괄 계산합니다.
 * 숨김 처리된 컴포넌트는 제외됩니다.
 * 
 * v5.1: 자동 줄바꿈 시스템으로 인해 모든 컴포넌트가 그리드 안에 배치되므로
 * "화면 밖" 개념이 제거되었습니다.
 */
export function getAllEffectivePositions(
  layout: PopLayoutDataV5,
  mode: GridMode
): Map<string, PopGridPosition> {
  const result = new Map<string, PopGridPosition>();
  
  // 숨김 처리된 컴포넌트 ID 목록
  const hiddenIds = layout.overrides?.[mode]?.hidden || [];
  
  // 자동 재배치 위치 미리 계산
  const componentsArray = Object.entries(layout.components).map(([id, comp]) => ({
    id,
    position: comp.position,
  }));
  const autoResolvedPositions = convertAndResolvePositions(componentsArray, mode);
  
  // 각 컴포넌트의 유효 위치 계산
  Object.keys(layout.components).forEach(componentId => {
    // 숨김 처리된 컴포넌트는 제외
    if (hiddenIds.includes(componentId)) {
      return;
    }
    
    const position = getEffectiveComponentPosition(
      componentId, 
      layout, 
      mode, 
      autoResolvedPositions
    );
    
    // v5.1: 자동 줄바꿈으로 인해 모든 컴포넌트가 그리드 안에 있음
    // 따라서 추가 필터링 불필요
    if (position) {
      result.set(componentId, position);
    }
  });
  
  return result;
}
