/**
 * Deck.gl 선박 레이어
 * 참조: mda-react-front/src/common/deck.ts
 * 참조: mda-react-front/src/util/realTimeLayerUtil.ts
 */
import { IconLayer, TextLayer, ScatterplotLayer, LineLayer, PathLayer } from '@deck.gl/layers';
import { fromLonLat, toLonLat } from 'ol/proj';
import {
  ICON_ATLAS_MAPPING,
  ICON_MAPPING_KIND_MOVING,
  ICON_MAPPING_KIND_STOPPING,
  SPEED_THRESHOLD,
  SIGNAL_KIND_CODE_BUOY,
  SIGNAL_FLAG_CONFIGS,
} from '../../types/constants';
import useShipStore from '../../stores/shipStore';
import useTrackingModeStore from '../../stores/trackingModeStore';
import { useMapStore, THEME_COLORS, THEME_TYPES } from '../../stores/mapStore';

// 아이콘 아틀라스 이미지
import atlasImg from '../../assets/img/icon/atlas.png';

/**
 * 현재 테마 색상 가져오기
 * @returns {Object} 테마 색상 객체
 */
function getCurrentThemeColors() {
  const { getTheme } = useMapStore.getState();
  const theme = getTheme();
  return THEME_COLORS[theme] || THEME_COLORS[THEME_TYPES.LIGHT];
}

// 추적 선박 아이콘 (인라인 SVG data URL)
const TRACKED_SHIP_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
  <circle cx="16" cy="16" r="14" stroke="#00D4FF" stroke-width="2" fill="none" stroke-dasharray="4 2"/>
  <circle cx="16" cy="16" r="10" fill="#00D4FF" fill-opacity="0.3"/>
  <path d="M16 6 L22 20 L16 17 L10 20 Z" fill="#00D4FF"/>
  <circle cx="16" cy="14" r="2" fill="#FFFFFF"/>
</svg>`;
const TRACKED_SHIP_ICON_URL = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(TRACKED_SHIP_SVG)}`;

// =====================
// 도 → 라디안 변환 상수
// =====================
const DEG_TO_RAD = 0.0174533; // Math.PI / 180

// =====================
// 클러스터링 캐시
// 줌 레벨 + isIntegrate 상태 + 렌더 트리거 기반 갱신
// 참조: mda-react-front/src/util/realTimeLayerUtil.ts (라인 327-363)
// =====================
const clusterCache = {
  lastZoom: null,
  lastDataLength: 0,
  lastIsIntegrate: null,
  lastRenderTrigger: 0,
  clusteredData: [],
  // 선박 위치 샘플 해시 (변경 감지용)
  positionHash: '',
};

// 신호상태 레이어용 별도 캐시
const signalClusterCache = {
  lastZoom: null,
  lastDataLength: 0,
  lastIsIntegrate: null,
  lastRenderTrigger: 0,
  clusteredData: [],
  positionHash: '',
  // 밀도 제한된 ships 배열 변경 감지용
  lastShipsLength: 0,
  lastShipsHash: '',
};

// 클러스터 갱신 주기 (N회 렌더링마다 재계산)
const CLUSTER_REFRESH_INTERVAL = 3;

// 클러스터 그리드 크기 배율 상수
const CLUSTER_GRID_SIZE_LABEL = 50;  // 라벨/선박명용 (기본)
const CLUSTER_GRID_SIZE_SIGNAL = 35; // 신호상태용 (더 조밀하게 표시)

/**
 * 그리드 기반 클러스터링 (개선된 버전)
 * - 줌 레벨이 높을수록 더 많은 선박 표시 (점진적 증가)
 * - 낮은 줌에서 표시된 선박은 높은 줌에서도 반드시 표시
 *
 * @param {Array} data - 선박 데이터 배열
 * @param {number} zoomLevel - 현재 줌 레벨
 * @param {number} gridSizeMultiplier - 그리드 크기 배율 (기본: 50)
 * @returns {Array} 클러스터링된 선박 배열
 */
function clusterPoints(data, zoomLevel, gridSizeMultiplier = CLUSTER_GRID_SIZE_LABEL) {
  // 그리드 크기: 줌 레벨이 높을수록 작은 그리드
  const gridSize = Math.pow(2, -zoomLevel) * gridSizeMultiplier;
  const clusters = {};

  // 1단계: 그리드별 선박 그룹화
  const len = data.length;
  for (let i = 0; i < len; i++) {
    const item = data[i];
    const gridX = Math.floor(item.longitude / gridSize);
    const gridY = Math.floor(item.latitude / gridSize);
    const gridKey = `${gridX},${gridY}`;

    if (!clusters[gridKey]) {
      clusters[gridKey] = [];
    }
    clusters[gridKey].push(item);
  }

  // 2단계: 각 그리드에서 대표 선박 선택
  // 우선순위: 신호상태 있음 > 선박명 있음 > 첫 번째
  const clusterKeys = Object.keys(clusters);
  const result = [];

  for (let i = 0; i < clusterKeys.length; i++) {
    const clusterShips = clusters[clusterKeys[i]];

    // 우선순위에 따라 대표 선박 선택
    let representative = clusterShips[0];

    for (let j = 0; j < clusterShips.length; j++) {
      const ship = clusterShips[j];
      // 신호상태가 있는 선박 우선 (통합선박이거나 신호원 정보가 있음)
      const hasSignalInfo = ship.signalSourceCode || ship.ais || ship.vpass || ship.enav;
      const hasName = ship.shipName && ship.shipName.trim();

      const repHasSignalInfo = representative.signalSourceCode || representative.ais || representative.vpass || representative.enav;
      const repHasName = representative.shipName && representative.shipName.trim();

      // 더 나은 대표 선박 선택
      if ((hasSignalInfo && !repHasSignalInfo) ||
          (hasSignalInfo === repHasSignalInfo && hasName && !repHasName)) {
        representative = ship;
      }
    }

    result.push(representative);
  }

  return result;
}

/**
 * 선박 위치 해시 생성 (샘플링)
 * 처음/중간/마지막 선박 위치를 해시로 변환
 * @param {Array} ships - 선박 배열
 * @returns {string} 위치 해시
 */
function computePositionHash(ships) {
  if (ships.length === 0) return '';

  // 샘플링: 처음, 중간, 마지막 선박 위치
  const indices = [0, Math.floor(ships.length / 2), ships.length - 1];
  const samples = indices.map(i => {
    const ship = ships[Math.min(i, ships.length - 1)];
    // 소수점 4자리까지만 (약 10m 정밀도)
    return `${ship.longitude.toFixed(4)},${ship.latitude.toFixed(4)}`;
  });

  return samples.join('|');
}

/**
 * 캐시된 클러스터링 결과 가져오기
 * - 줌 레벨, isIntegrate 변경 시 재계산
 * - 렌더 트리거 주기에 따라 갱신 (선박 위치 변경 반영)
 *
 * @param {Array} ships - 선박 데이터 배열
 * @param {number} zoom - 현재 줌 레벨
 * @param {boolean} isIntegrate - 선박통합 모드 여부
 * @param {number} renderTrigger - 렌더링 트리거 (배치 렌더러에서 증가)
 * @returns {Array} 클러스터링된 선박 배열
 */
function getClusteredShips(ships, zoom, isIntegrate, renderTrigger = 0) {
  const zoomInt = Math.floor(zoom);
  const positionHash = computePositionHash(ships);

  // 캐시 유효 조건
  const zoomMatch = clusterCache.lastZoom === zoomInt;
  const integrateMatch = clusterCache.lastIsIntegrate === isIntegrate;
  const sizeMatch = Math.abs(clusterCache.lastDataLength - ships.length) < ships.length * 0.1;
  const positionMatch = clusterCache.positionHash === positionHash;

  // 렌더 트리거 주기 체크 (N회마다 강제 갱신)
  const triggerDiff = renderTrigger - clusterCache.lastRenderTrigger;
  const needsPeriodicRefresh = triggerDiff >= CLUSTER_REFRESH_INTERVAL;

  // 캐시 히트 조건: 모든 조건 만족 + 주기적 갱신 불필요
  if (zoomMatch && integrateMatch && sizeMatch && positionMatch && !needsPeriodicRefresh) {
    return clusterCache.clusteredData;
  }

  // 새로 클러스터링 계산
  const clustered = clusterPoints(ships, zoomInt);

  // 캐시 업데이트
  clusterCache.lastZoom = zoomInt;
  clusterCache.lastDataLength = ships.length;
  clusterCache.lastIsIntegrate = isIntegrate;
  clusterCache.lastRenderTrigger = renderTrigger;
  clusterCache.positionHash = positionHash;
  clusterCache.clusteredData = clustered;

  return clustered;
}

/**
 * 클러스터 캐시 초기화
 */
export function clearClusterCache() {
  clusterCache.lastZoom = null;
  clusterCache.lastDataLength = 0;
  clusterCache.lastIsIntegrate = null;
  clusterCache.lastRenderTrigger = 0;
  clusterCache.positionHash = '';
  clusterCache.clusteredData = [];

  signalClusterCache.lastZoom = null;
  signalClusterCache.lastDataLength = 0;
  signalClusterCache.lastIsIntegrate = null;
  signalClusterCache.lastRenderTrigger = 0;
  signalClusterCache.positionHash = '';
  signalClusterCache.clusteredData = [];
  signalClusterCache.lastShipsLength = 0;
  signalClusterCache.lastShipsHash = '';
}

/**
 * 실제로 신호상태 SVG가 생성 가능한지 체크
 * @param {Object} ship - 선박 데이터
 * @param {boolean} isIntegrate - 선박통합 모드 여부
 * @returns {boolean} SVG 생성 가능 여부
 */
function canGenerateSignalSVG(ship, isIntegrate) {
  if (isIntegrate && isIntegratedShip(ship)) {
    // 통합선박 + 선박통합 ON: 장비 값이 '0' 또는 '1'인 것이 하나라도 있어야 함
    return ship.ais === '0' || ship.ais === '1' ||
           ship.vpass === '0' || ship.vpass === '1' ||
           ship.enav === '0' || ship.enav === '1' ||
           ship.vtsAis === '0' || ship.vtsAis === '1' ||
           ship.dMfHf === '0' || ship.dMfHf === '1' ||
           ship.vtsRadar === '0' || ship.vtsRadar === '1';
  } else {
    // 단독선박 또는 선박통합 OFF: signalSourceCode가 있으면 SVG 생성 가능
    return !!ship.signalSourceCode;
  }
}

/**
 * ships 배열의 featureId 해시 생성 (배열 변경 감지용)
 * @param {Array} ships - 선박 배열
 * @returns {string} featureId 기반 해시
 */
function computeShipsHash(ships) {
  if (ships.length === 0) return '';
  // 처음, 1/4, 중간, 3/4, 마지막 선박의 featureId를 샘플링
  const indices = [
    0,
    Math.floor(ships.length / 4),
    Math.floor(ships.length / 2),
    Math.floor(ships.length * 3 / 4),
    ships.length - 1
  ];
  return indices.map(i => ships[Math.min(i, ships.length - 1)]?.featureId || '').join('|');
}

/**
 * 신호상태용 클러스터링 결과 가져오기
 * 실제로 SVG가 생성 가능한 선박만 대상으로 클러스터링
 *
 * @param {Array} ships - 필터링된 선박 데이터 배열 (지도에 그려지는 선박)
 * @param {number} zoom - 현재 줌 레벨
 * @param {boolean} isIntegrate - 선박통합 모드 여부
 * @param {number} renderTrigger - 렌더링 트리거
 * @returns {Array} 클러스터링된 선박 배열
 */
function getSignalClusteredShips(ships, zoom, isIntegrate, renderTrigger = 0) {
  const zoomInt = Math.floor(zoom);

  // ships 배열 변경 감지용 해시 (밀도 제한 결과가 달라지면 캐시 무효화)
  const shipsHash = computeShipsHash(ships);
  const shipsLengthMatch = signalClusterCache.lastShipsLength === ships.length;
  const shipsHashMatch = signalClusterCache.lastShipsHash === shipsHash;

  // 실제로 SVG 생성 가능한 선박만 필터링
  const shipsWithSignal = ships.filter(ship => canGenerateSignalSVG(ship, isIntegrate));
  const positionHash = computePositionHash(shipsWithSignal);

  // 캐시 유효 조건 (ships 배열 변경도 감지)
  const zoomMatch = signalClusterCache.lastZoom === zoomInt;
  const integrateMatch = signalClusterCache.lastIsIntegrate === isIntegrate;
  const sizeMatch = Math.abs(signalClusterCache.lastDataLength - shipsWithSignal.length) < Math.max(1, shipsWithSignal.length * 0.1);
  const positionMatch = signalClusterCache.positionHash === positionHash;

  // 렌더 트리거 주기 체크
  const triggerDiff = renderTrigger - signalClusterCache.lastRenderTrigger;
  const needsPeriodicRefresh = triggerDiff >= CLUSTER_REFRESH_INTERVAL;

  // 캐시 히트: 모든 조건 충족 시에만 (ships 배열 변경도 체크)
  if (zoomMatch && integrateMatch && sizeMatch && positionMatch && shipsLengthMatch && shipsHashMatch && !needsPeriodicRefresh) {
    return signalClusterCache.clusteredData;
  }

  // 클러스터링 (SVG 생성 가능한 선박만 대상, 신호상태용 작은 그리드 사용)
  const clustered = clusterPoints(shipsWithSignal, zoomInt, CLUSTER_GRID_SIZE_SIGNAL);

  // 캐시 업데이트
  signalClusterCache.lastZoom = zoomInt;
  signalClusterCache.lastDataLength = shipsWithSignal.length;
  signalClusterCache.lastIsIntegrate = isIntegrate;
  signalClusterCache.lastRenderTrigger = renderTrigger;
  signalClusterCache.positionHash = positionHash;
  signalClusterCache.clusteredData = clustered;
  signalClusterCache.lastShipsLength = ships.length;
  signalClusterCache.lastShipsHash = shipsHash;

  return clustered;
}

// =====================
// 속도벡터 스케일 (SOG 기반)
// 참조: mda-react-front/src/common/deck.ts (라인 708)
//
// 개선: 최소 길이 보장 + 속도 증가에 따른 점진적 증가
// - 최소 길이: 항해중 아이콘(SPEED_THRESHOLD 기준) 크기보다 충분히 길게
// - 추가 길이: 속도 증가분에 비례하여 완만하게 증가
// =====================
const VECTOR_MIN_LENGTH = 500;       // 최소 벡터 길이 (투영좌표 단위, 약 500m)
const VECTOR_INCREMENT_SCALE = 40;   // 속도 1kn 증가당 추가 길이

/**
 * 선박 아이콘 결정
 * @param {Object} ship - 선박 데이터
 * @returns {string} 아이콘 이름 (ICON_ATLAS_MAPPING 키)
 */
export function getShipIcon(ship, darkSignalIds) {
  // 다크시그널(소실신호): darkSignalIds Set으로 판단
  if (darkSignalIds && darkSignalIds.has(ship.featureId)) {
    return 'lostShipImg';
  }

  // 속력에 따른 이동/정지 판단
  const isMoving = Number(ship.sog) > SPEED_THRESHOLD;

  if (isMoving) {
    return ICON_MAPPING_KIND_MOVING[ship.signalKindCode] || 'etcImg';
  } else {
    return ICON_MAPPING_KIND_STOPPING[ship.signalKindCode] || 'etcStopImg';
  }
}

/**
 * 선박 회전 각도 계산 (COG 기준)
 * 참조: mda-react-front/src/util/realTimeLayerUtil.ts - targetAngle()
 *
 * @param {Object} ship - 선박 데이터
 * @returns {number} 회전 각도 (degrees)
 */
export function getShipAngle(ship) {
  // 부이는 회전하지 않음
  if (ship.signalKindCode === SIGNAL_KIND_CODE_BUOY) {
    return 0;
  }

  // COG (Course Over Ground) 기준 회전
  // 메인 프로젝트와 동일하게 -COG 적용
  return -Number(ship.cog) || 0;
}

/**
 * 선박 크기 결정 (운항/정박 상태 + 줌 레벨)
 * 참조: mda-react-front/src/util/realTimeLayerUtil.ts - targetScale()
 *
 * @param {Object} ship - 선박 데이터
 * @param {number} zoom - 현재 줌 레벨
 * @returns {number} 아이콘 크기 (px)
 */
export function getShipSize(ship, zoom) {
  // 부이: 항상 16px
  if (ship.signalKindCode === SIGNAL_KIND_CODE_BUOY) {
    return 16;
  }

  // 정박 선박 (SOG ≤ 1): 항상 8px
  const isMoving = Number(ship.sog) > SPEED_THRESHOLD;
  if (!isMoving) {
    return 8;
  }

  // 운항 선박: 줌 레벨에 따른 크기
  if (zoom < 8) {
    return 15;
  } else if (zoom < 11) {
    return 25;
  } else if (zoom < 14) {
    return 35;
  } else {
    return 40;
  }
}

/**
 * 선박 IconLayer 생성
 * @param {Array} ships - 선박 데이터 배열
 * @param {number} zoom - 현재 줌 레벨
 * @returns {IconLayer} Deck.gl IconLayer
 */
export function createShipIconLayer(ships, zoom = 10, darkSignalIds = null) {
  return new IconLayer({
    id: 'ship-icon-layer',
    data: ships,
    pickable: true,
    iconAtlas: atlasImg,
    iconMapping: ICON_ATLAS_MAPPING,
    getPosition: (d) => [d.longitude, d.latitude],
    getIcon: (d) => getShipIcon(d, darkSignalIds),
    getAngle: (d) => getShipAngle(d),
    getSize: (d) => getShipSize(d, zoom),
    sizeScale: 1,
    sizeMinPixels: 6,
    sizeMaxPixels: 50,
  });
}

// =====================
// 속도벡터 LineLayer
// 참조: mda-react-front/src/common/deck.ts (라인 702-715)
// =====================

/**
 * 속도벡터 데이터 생성
 * COG(방향)와 SOG(속도)를 사용하여 벡터 끝점 계산
 * 투영좌표(EPSG:3857)에서 계산 후 경위도로 변환
 *
 * 벡터 길이 계산:
 * - 최소 길이(VECTOR_MIN_LENGTH) + 속도 초과분 * 증가율(VECTOR_INCREMENT_SCALE)
 * - SPEED_THRESHOLD(1kn) 기준으로 항해중 아이콘과 함께 표시
 *
 * @param {Array} ships - 선박 데이터 배열
 * @returns {Array} 라인 데이터 [{ sourcePosition, targetPosition, color }]
 */
function buildSpeedVectorData(ships) {
  // 테마 기반 색상
  const themeColors = getCurrentThemeColors();
  const vectorColor = themeColors.speedVector;

  return ships
    .filter((ship) => Number(ship.sog) > SPEED_THRESHOLD) // 항해중 선박만 (아이콘 기준과 동일)
    .map((ship) => {
      const lng = Number(ship.longitude);
      const lat = Number(ship.latitude);
      const cog = Number(ship.cog) || 0;
      const sog = Number(ship.sog) || 0;

      // 투영좌표로 변환 (EPSG:3857 - Web Mercator)
      const coordinate = fromLonLat([lng, lat]);
      const projX = coordinate[0];
      const projY = coordinate[1];

      // 벡터 길이 계산: 최소 길이 + 속도 초과분에 비례한 추가 길이
      // 예: 1kn → 500m, 5kn → 660m, 10kn → 860m, 20kn → 1260m
      const extraSpeed = Math.max(0, sog - SPEED_THRESHOLD);
      const vectorLength = VECTOR_MIN_LENGTH + extraSpeed * VECTOR_INCREMENT_SCALE;

      // COG 방향으로 벡터 계산
      // sin(COG): 동-서 방향, cos(COG): 남-북 방향
      const xAdd = Math.sin(cog * DEG_TO_RAD) * vectorLength;
      const yAdd = Math.cos(cog * DEG_TO_RAD) * vectorLength;

      // 경위도로 변환하여 반환
      return {
        sourcePosition: toLonLat([projX, projY]),
        targetPosition: toLonLat([projX + xAdd, projY + yAdd]),
        color: vectorColor,
      };
    });
}

/**
 * 속도벡터 LineLayer 생성
 * @param {Array} ships - 선박 데이터 배열
 * @param {number} zoom - 현재 줌 레벨
 * @returns {LineLayer|null} Deck.gl LineLayer
 */
export function createSpeedVectorLayer(ships, zoom) {
  // 줌 9 이상에서만 표시
  if (zoom < 9) {
    return null;
  }

  const vectorData = buildSpeedVectorData(ships);
  if (vectorData.length === 0) {
    return null;
  }

  return new LineLayer({
    id: 'speed-vector-layer',
    data: vectorData,
    pickable: false,
    getSourcePosition: (d) => d.sourcePosition,
    getTargetPosition: (d) => d.targetPosition,
    getColor: (d) => d.color,
    getWidth: 2,
    widthMinPixels: 1,
    widthMaxPixels: 3,
  });
}

// =====================
// 선박크기 (DIM) 폴리곤 레이어
// 참조: mda-react-front/src/util/realTimeLayerUtil.ts - calDimension()
// =====================

// DIM 폴리곤 최소 줌 레벨 (14레벨 이상에서 실제 크기로 렌더링)
const DIM_POLYGON_MIN_ZOOM = 14;

/**
 * 선박 크기 폴리곤 계산 (dimABCD 기준)
 * 참조점(안테나 위치)을 기준으로 선박 형태 폴리곤 생성
 *
 * dimA: 참조점 → 뱃머리(bow) 거리
 * dimB: 참조점 → 선미(stern) 거리
 * dimC: 참조점 → 좌현(port) 거리
 * dimD: 참조점 → 우현(starboard) 거리
 *
 * @param {number} projX - 투영좌표 X (선박 위치)
 * @param {number} projY - 투영좌표 Y (선박 위치)
 * @param {number} dimA - 뱃머리 거리 (m)
 * @param {number} dimB - 선미 거리 (m)
 * @param {number} dimC - 좌현 거리 (m)
 * @param {number} dimD - 우현 거리 (m)
 * @param {number} angleS - sin(360 - COG)
 * @param {number} angleC - cos(360 - COG)
 * @returns {Array} 경위도 좌표 배열 (6점 폴리곤)
 */
function calDimension(projX, projY, dimA, dimB, dimC, dimD, angleS, angleC) {
  // 좌상단 (좌현, 뱃머리 3/4)
  let leftTopX = -1 * dimC;
  let leftTopY = (dimA * 3) / 4;
  let xNew = leftTopX * angleC - leftTopY * angleS;
  let yNew = leftTopX * angleS + leftTopY * angleC;
  leftTopX = xNew + projX;
  leftTopY = yNew + projY;

  // 좌하단 (좌현, 선미)
  let leftBottomX = -1 * dimC;
  let leftBottomY = -1 * dimB;
  xNew = leftBottomX * angleC - leftBottomY * angleS;
  yNew = leftBottomX * angleS + leftBottomY * angleC;
  leftBottomX = xNew + projX;
  leftBottomY = yNew + projY;

  // 우하단 (우현, 선미)
  let rightBottomX = dimD;
  let rightBottomY = -1 * dimB;
  xNew = rightBottomX * angleC - rightBottomY * angleS;
  yNew = rightBottomX * angleS + rightBottomY * angleC;
  rightBottomX = xNew + projX;
  rightBottomY = yNew + projY;

  // 우상단 (우현, 뱃머리 3/4)
  let rightTopX = dimD;
  let rightTopY = (dimA * 3) / 4;
  xNew = rightTopX * angleC - rightTopY * angleS;
  yNew = rightTopX * angleS + rightTopY * angleC;
  rightTopX = xNew + projX;
  rightTopY = yNew + projY;

  // 선수 중앙 (뱃머리 끝)
  let centerTopX = (dimD - dimC) / 2;
  let centerTopY = dimA;
  xNew = centerTopX * angleC - centerTopY * angleS;
  yNew = centerTopX * angleS + centerTopY * angleC;
  centerTopX = xNew + projX;
  centerTopY = yNew + projY;

  // 6점 폴리곤 (시작점으로 복귀)
  return [
    toLonLat([leftTopX, leftTopY]),
    toLonLat([leftBottomX, leftBottomY]),
    toLonLat([rightBottomX, rightBottomY]),
    toLonLat([rightTopX, rightTopY]),
    toLonLat([centerTopX, centerTopY]),
    toLonLat([leftTopX, leftTopY]),
  ];
}

/**
 * 선박 크기 폴리곤 계산 (길이/너비만 있는 경우)
 * 중심점 기준으로 사각형 + 선수 형태 생성
 *
 * @param {number} projX - 투영좌표 X (선박 중심)
 * @param {number} projY - 투영좌표 Y (선박 중심)
 * @param {number} length - 선박 총 길이 (m)
 * @param {number} width - 선박 총 너비 (m)
 * @param {number} angleS - sin(360 - COG)
 * @param {number} angleC - cos(360 - COG)
 * @returns {Array} 경위도 좌표 배열 (6점 폴리곤)
 */
function calDimensionCentered(projX, projY, length, width, angleS, angleC) {
  // 중심 기준이므로 dimA = dimB = length/2, dimC = dimD = width/2
  const dimA = length / 2; // 뱃머리
  const dimB = length / 2; // 선미
  const dimC = width / 2;  // 좌현
  const dimD = width / 2;  // 우현

  return calDimension(projX, projY, dimA, dimB, dimC, dimD, angleS, angleC);
}

/**
 * 선박 DIM 폴리곤 데이터 생성
 * dimABCD 우선, 없으면 길이/너비로 중심 기준 폴리곤 생성
 *
 * @param {Array} ships - 뷰포트 내 선박 배열
 * @returns {Array} 폴리곤 경로 데이터
 */
function buildDimPolygonData(ships) {
  const result = [];

  for (const ship of ships) {
    const dimA = Number(ship.dimA) || 0;
    const dimB = Number(ship.dimB) || 0;
    const dimC = Number(ship.dimC) || 0;
    const dimD = Number(ship.dimD) || 0;

    // 투영좌표 변환
    const coordinate = fromLonLat([Number(ship.longitude), Number(ship.latitude)]);
    const projX = coordinate[0];
    const projY = coordinate[1];

    // 회전 각도 계산 (COG 기준)
    const cog = Number(ship.cog) || 0;
    const angleS = Math.sin(((360 - cog) * Math.PI) / 180.0);
    const angleC = Math.cos(((360 - cog) * Math.PI) / 180.0);

    let path = null;

    // 케이스 1: dimABCD가 모두 있는 경우 (참조점 기준)
    if (dimA > 0) {
      path = calDimension(projX, projY, dimA, dimB, dimC, dimD, angleS, angleC);
    }
    // 케이스 2: dimABCD가 없지만 총 길이/너비 계산 가능한 경우 (중심 기준)
    else {
      const totalLength = dimA + dimB;
      const totalWidth = dimC + dimD;

      // 길이 또는 너비가 있어야 폴리곤 생성
      if (totalLength > 0 || totalWidth > 0) {
        // 길이만 있는 경우 기본 너비 할당 (시각화용)
        const effectiveLength = totalLength > 0 ? totalLength : 10;
        const effectiveWidth = totalWidth > 0 ? totalWidth : Math.max(3, effectiveLength * 0.15);

        path = calDimensionCentered(projX, projY, effectiveLength, effectiveWidth, angleS, angleC);
      }
    }

    if (path) {
      result.push({
        path,
        featureId: ship.featureId,
      });
    }
  }

  return result;
}

/**
 * 선박크기 PathLayer 생성
 * 줌 레벨 11 이상에서만 렌더링
 *
 * @param {Array} ships - 뷰포트 내 선박 배열
 * @param {number} zoom - 현재 줌 레벨
 * @returns {PathLayer|null} Deck.gl PathLayer
 */
export function createShipDimLayer(ships, zoom) {
  // 줌 레벨 11 미만이면 null 반환
  if (zoom < DIM_POLYGON_MIN_ZOOM) {
    return null;
  }

  const dimData = buildDimPolygonData(ships);

  if (dimData.length === 0) {
    return null;
  }

  // 테마 기반 색상
  const themeColors = getCurrentThemeColors();

  return new PathLayer({
    id: 'ship-dim-layer',
    data: dimData,
    pickable: false,
    widthScale: 1,
    widthMinPixels: 1,
    widthMaxPixels: 3,
    getPath: (d) => d.path,
    getColor: themeColors.shipDim,
    getWidth: 2,
    jointRounded: true,
    capRounded: true,
  });
}

// =====================
// 신호상태 SVG 캐싱 시스템
// 참조: mda-react-front/src/util/realTimeLayerUtil.ts (라인 778-876)
// =====================

// SVG 캐시 맵
const flagSvgCache = new Map();

/**
 * 통합선박 여부 판별
 * @param {Object} ship - 선박 객체
 * @returns {boolean} 통합선박 여부
 */
function isIntegratedShip(ship) {
  return ship.targetId && (ship.targetId.includes('_') || ship.integrate);
}

/**
 * 통합선박의 장비 플래그 병합
 * 동일 targetId를 공유하는 모든 feature의 장비 플래그를 합산
 * 예: 레이더 feature(vtsRadar='1') + AIS feature(ais='1') → { ais:'1', vtsRadar:'1' }
 * '1'(활성) > '0'(비활성) > ''(없음) 우선순위로 병합
 * @returns {Map<string, Object>} targetId → 병합된 장비 플래그
 */
function buildMergedEquipmentFlags() {
  const { features } = useShipStore.getState();
  const map = new Map();

  features.forEach((ship) => {
    const targetId = ship.targetId;
    if (!targetId || !isIntegratedShip(ship)) return;

    const existing = map.get(targetId) || {};
    for (const config of SIGNAL_FLAG_CONFIGS) {
      const key = config.dataKey;
      const val = ship[key];
      // '1'이면 무조건 설정, '0'은 기존이 '1'이 아닐 때만
      if (val === '1') {
        existing[key] = '1';
      } else if (val === '0' && existing[key] !== '1') {
        existing[key] = '0';
      }
    }
    map.set(targetId, existing);
  });

  return map;
}

/**
 * 신호 상태 배열 생성 (캐시 키 + SVG 생성용)
 * 참조: mda-react-front/src/util/realTimeLayerUtil.ts
 *
 * 선박통합 ON + 통합선박 (TARGET_ID에 '_' 포함):
 *   - '1' = 장비 존재 + 활성 (activeColor)
 *   - '0' = 장비 존재 + 비활성 (inactiveColor/회색)
 *   - '' = 장비 없음 (표시 안함)
 *
 * 선박통합 OFF 또는 단독선박:
 *   - 현재 signalSourceCode에 해당하는 장비만 표시 (항상 활성 색상)
 *
 * @param {Object} ship - 선박 데이터
 * @param {boolean} isIntegrate - 선박통합 모드 여부
 * @returns {Object} { key, flagArray }
 */
function buildFlagStateArray(ship, isIntegrate) {
  const keyParts = [];
  const flagArray = [];

  // 선박통합 ON이고 통합선박인 경우에만 통합 모드로 처리
  const useIntegratedMode = isIntegrate && isIntegratedShip(ship);

  for (const config of SIGNAL_FLAG_CONFIGS) {
    let isVisible = false;
    let isActive = false;
    let color = config.inactiveColor;

    if (useIntegratedMode) {
      // 통합선박 + 선박통합 ON: 장비 값 확인
      const dataValue = ship[config.dataKey];

      // '' 또는 undefined → 장비 없음 (표시 안함)
      // '0' → 장비 존재, 비활성 (회색)
      // '1' → 장비 존재, 활성 (색상)
      if (dataValue === '1') {
        isVisible = true;
        isActive = true;
        color = config.activeColor;
      } else if (dataValue === '0') {
        isVisible = true;
        isActive = false;
        color = config.inactiveColor;
      }
      // dataValue가 '' 또는 undefined면 isVisible = false 유지
    } else {
      // 선박통합 OFF 또는 단독선박: 현재 신호원만 표시 (항상 활성 색상)
      if (config.signalSourceCode === ship.signalSourceCode) {
        isVisible = true;
        isActive = true;
        color = config.activeColor;
      }
    }

    // 캐시 키: I(통합모드)/S(단독모드) + X(미표시)/0(비활성)/1(활성)
    const modePrefix = useIntegratedMode ? 'I' : 'S';
    keyParts.push(modePrefix + (isVisible ? (isActive ? '1' : '0') : 'X'));

    flagArray.push({
      name: config.key,
      color: color,
      flag: isVisible ? (isActive ? '1' : '0') : '',
    });
  }

  return {
    key: keyParts.join('_'),
    flagArray,
  };
}

/**
 * 신호 플래그 SVG 생성
 * 참조: mda-react-front/src/util/realTimeLayerUtil.ts - createFlagLabelSVG()
 * @param {Array} arr - 플래그 배열
 * @returns {string} SVG 문자열
 */
function createFlagLabelSVG(arr) {
  const filteredArr = arr.filter((v) => v.flag !== '');
  if (filteredArr.length === 0) {
    return '';
  }

  const rectSize = 20;
  const gap = 1.1;
  const svgSize = 128;
  const totalRectWidth = filteredArr.length * rectSize + (filteredArr.length - 1) * gap;
  const offsetX = (svgSize - totalRectWidth) / 2;
  let rects = '';
  let currentIndex = 0;

  for (let i = 0; i < arr.length; i++) {
    if (arr[i].flag === '') {
      continue;
    }
    const x = offsetX + currentIndex * (rectSize + gap);
    rects += `<rect x="${x}" y="${(svgSize - rectSize) / 2}" width="${rectSize}" height="${rectSize}" fill="${arr[i].color}"></rect>`;
    rects += `<text x="${x + rectSize / 2}" y="${svgSize / 2 + 4}" font-size="13" fill="white" text-anchor="middle">${arr[i].name}</text>`;
    currentIndex++;
  }

  const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${svgSize}" height="${svgSize}" viewBox="0 0 ${svgSize} 60">${rects}</svg>`;
  return svg.replace(/\s+/g, ' ');
}

/**
 * SVG를 Data URI로 변환
 * @param {string} svgStr - SVG 문자열
 * @returns {string} Data URI
 */
function svgToDataURI(svgStr) {
  return `data:image/svg+xml;charset=utf8,${encodeURIComponent(svgStr)}`;
}

/**
 * 캐시된 신호 플래그 SVG 가져오기
 * @param {Object} ship - 선박 데이터
 * @param {boolean} isIntegrate - 선박통합 모드 여부
 * @returns {string} SVG 문자열
 */
function getCachedFlagSVG(ship, isIntegrate) {
  const { key, flagArray } = buildFlagStateArray(ship, isIntegrate);

  let svg = flagSvgCache.get(key);
  if (!svg) {
    svg = createFlagLabelSVG(flagArray);
    if (svg) {
      flagSvgCache.set(key, svg);
    }
  }

  return svg || '';
}

/**
 * SVG 캐시 초기화
 */
export function clearFlagSvgCache() {
  flagSvgCache.clear();
}

/**
 * 신호상태 IconLayer 생성 (SVG 캐싱 사용)
 * 참조: mda-react-front/src/common/deck.ts (라인 757-771)
 * @param {Array} ships - 선박 데이터 배열
 * @param {number} zoom - 현재 줌 레벨
 * @param {boolean} isIntegrate - 선박통합 모드 여부
 * @returns {IconLayer|null} Deck.gl IconLayer
 */
export function createSignalStatusLayer(ships, zoom, isIntegrate) {
  if (zoom < 9) {
    return null;
  }

  // 통합모드: 동일 targetId의 모든 feature에서 장비 플래그 병합
  // 대표 feature(예: 레이더)에는 자기 장비 플래그만 있으므로,
  // 같은 targetId를 공유하는 다른 feature(AIS 등)의 플래그를 합쳐야 함
  let mergedFlagsMap = null;
  if (isIntegrate) {
    mergedFlagsMap = buildMergedEquipmentFlags();
  }

  // 신호 플래그 데이터 생성 (SVG 캐싱 적용)
  const flagData = ships
    .map((ship) => {
      // 통합선박이면 병합된 장비 플래그 적용
      let effectiveShip = ship;
      if (mergedFlagsMap && ship.targetId && ship.targetId.includes('_')) {
        const merged = mergedFlagsMap.get(ship.targetId);
        if (merged) {
          effectiveShip = { ...ship, ...merged };
        }
      }

      const svg = getCachedFlagSVG(effectiveShip, isIntegrate);
      if (!svg) return null;

      return {
        longitude: Number(ship.longitude),
        latitude: Number(ship.latitude),
        url: svg,
      };
    })
    .filter((d) => d !== null);

  if (flagData.length === 0) {
    return null;
  }

  return new IconLayer({
    id: 'signal-status-layer',
    data: flagData,
    pickable: false,
    sizeScale: 15,
    getPixelOffset: [20, 20], // 선박명 옆, 아래 배치
    getPosition: (d) => [d.longitude, d.latitude],
    getIcon: (d) => ({
      url: svgToDataURI(d.url),
      width: 128,
      height: 128,
      anchorY: 64, // 중앙 정렬
    }),
    getSize: 10,
  });
}

// =====================
// 선박명 TextLayer
// =====================

/**
 * 선박 라벨 텍스트 생성
 * @param {Object} ship - 선박 데이터
 * @param {Object} labelOptions - 라벨 옵션
 * @returns {string} 라벨 텍스트
 */
function buildLabelText(ship, labelOptions) {
  const parts = [];

  // 선박명
  if (labelOptions.showShipName && ship.shipName) {
    parts.push(ship.shipName);
  }

  // 선박크기 (DIM)
  if (labelOptions.showShipSize) {
    const length = (Number(ship.dimA) || 0) + (Number(ship.dimB) || 0);
    const width = (Number(ship.dimC) || 0) + (Number(ship.dimD) || 0);
    if (length > 0 || width > 0) {
      parts.push(`${length}m x ${width}m`);
    }
  }

  return parts.join('\n');
}

/**
 * 선박명 TextLayer 생성
 * @param {Array} ships - 선박 데이터 배열
 * @param {number} zoom - 현재 줌 레벨
 * @param {Object} labelOptions - 라벨 옵션
 * @returns {TextLayer|null} Deck.gl TextLayer
 */
export function createShipLabelLayer(ships, zoom, labelOptions = { showShipName: true }) {
  if (zoom < 9) {
    return null;
  }

  const labelData = ships
    .map((ship) => ({
      ...ship,
      labelText: buildLabelText(ship, labelOptions),
    }))
    .filter((ship) => ship.labelText);

  if (labelData.length === 0) {
    return null;
  }

  const fontSize = zoom < 11 ? 10 : zoom < 13 ? 12 : 14;

  // 테마 기반 색상
  const themeColors = getCurrentThemeColors();

  return new TextLayer({
    id: 'ship-label-layer',
    data: labelData,
    pickable: false,
    getPosition: (d) => [d.longitude, d.latitude],
    getText: (d) => d.labelText,
    getSize: fontSize,
    getColor: themeColors.shipLabel,
    getAngle: 0,
    getTextAnchor: 'start',
    getAlignmentBaseline: 'center',
    getPixelOffset: [20, 0],
    fontFamily: 'NanumSquare, Malgun Gothic, 맑은 고딕, Arial, sans-serif',
    fontWeight: 'bold',
    characterSet: 'auto',
    outlineWidth: 2,
    outlineColor: themeColors.shipLabelOutline,
    billboard: true,
  });
}

/**
 * 선택된 선박 하이라이트 레이어 (다중 선박 지원)
 * @param {Array} selectedShips - 선택된 선박 데이터 배열
 * @returns {ScatterplotLayer|null} Deck.gl 레이어
 */
export function createSelectedShipLayer(selectedShips) {
  if (!selectedShips || selectedShips.length === 0) return null;

  return new ScatterplotLayer({
    id: 'selected-ship-layer',
    data: selectedShips,
    pickable: false,
    stroked: true,
    filled: false,
    radiusScale: 1,
    radiusMinPixels: 18,
    radiusMaxPixels: 35,
    lineWidthMinPixels: 2,
    getPosition: (d) => [d.longitude, d.latitude],
    getRadius: 25,
    getLineColor: [255, 215, 0, 255],
    getLineWidth: 3,
  });
}

/**
 * 추적 선박 레이어 (최상단 표시)
 * 선박 모드에서 추적 중인 함정을 특별 아이콘으로 표시
 * ScatterplotLayer로 원형 마커 + IconLayer로 아이콘 표시
 * @param {number} zoom - 현재 줌 레벨
 * @returns {Array} Deck.gl 레이어 배열
 */
export function createTrackedShipLayers(zoom) {
  const { mode, trackedShip } = useTrackingModeStore.getState();

  // 선박 모드가 아니거나 추적 중인 함정이 없으면 빈 배열
  if (mode !== 'ship' || !trackedShip || !trackedShip.longitude || !trackedShip.latitude) {
    return [];
  }

  const layers = [];

  // 위치 기반 업데이트 트리거 (좌표 변경 시 레이어 갱신)
  const positionKey = `${trackedShip.longitude.toFixed(6)}_${trackedShip.latitude.toFixed(6)}`;

  // 1. 외곽 원형 마커 (강조 효과)
  layers.push(new ScatterplotLayer({
    id: 'tracked-ship-outer-ring',
    data: [trackedShip],
    pickable: false,
    stroked: true,
    filled: false,
    radiusScale: 1,
    radiusMinPixels: 18,
    radiusMaxPixels: 35,
    lineWidthMinPixels: 2,
    getPosition: (d) => [d.longitude, d.latitude],
    getRadius: 22,
    getLineColor: [0, 212, 255, 180], // #00D4FF with alpha
    getLineWidth: 2,
    updateTriggers: {
      getPosition: positionKey,
    },
  }));

  // 2. 내부 원형 마커 (반투명)
  layers.push(new ScatterplotLayer({
    id: 'tracked-ship-inner-circle',
    data: [trackedShip],
    pickable: false,
    stroked: false,
    filled: true,
    radiusScale: 1,
    radiusMinPixels: 12,
    radiusMaxPixels: 25,
    getPosition: (d) => [d.longitude, d.latitude],
    getRadius: 15,
    getFillColor: [0, 212, 255, 60], // #00D4FF with more transparency
    updateTriggers: {
      getPosition: positionKey,
    },
  }));

  // 3. 중심점 (흰색)
  layers.push(new ScatterplotLayer({
    id: 'tracked-ship-center-dot',
    data: [trackedShip],
    pickable: true,
    stroked: false,
    filled: true,
    radiusScale: 1,
    radiusMinPixels: 3,
    radiusMaxPixels: 7,
    getPosition: (d) => [d.longitude, d.latitude],
    getRadius: 4,
    getFillColor: [255, 255, 255, 200], // white with slight transparency
    updateTriggers: {
      getPosition: positionKey,
    },
  }));

  return layers;
}

/**
 * 모든 선박 레이어 생성 (통합)
 * 참조: mda-react-front/src/common/deck.ts
 *
 * 렌더링 파이프라인:
 * 1. 밀도 제한 적용 (배치 렌더러) → 아이콘 표시 대상 결정
 * 2. 아이콘 레이어 생성 (밀도 제한된 ships 사용)
 * 3. 라벨 클러스터링 (밀도 제한된 ships 대상) → 라벨 표시 대상 결정
 * 4. 라벨/신호상태 레이어 생성
 *
 * @param {Array} ships - 선박 데이터 (밀도 제한 적용됨, 아이콘 + 라벨 공통)
 * @param {Object|null} selectedShip - 선택된 선박
 * @param {number} zoom - 현재 줌 레벨
 * @param {boolean} showLabels - 선명표시 여부
 * @param {Object} labelOptions - 선명표시 옵션
 * @param {boolean} isIntegrate - 선박통합 모드 여부
 * @param {number} renderTrigger - 렌더링 트리거 (배치 렌더러에서 증가)
 * @returns {Array} Deck.gl 레이어 배열
 */
export function createShipLayers(ships, selectedShips, zoom, showLabels = false, labelOptions = { showShipName: true }, isIntegrate = true, renderTrigger = 0, darkSignalIds = null) {
  const layers = [];

  // 1. 선택된 선박 하이라이트 (다중)
  const selectedLayer = createSelectedShipLayer(selectedShips);
  if (selectedLayer) {
    layers.push(selectedLayer);
  }

  // 2. 선박 아이콘 레이어 (밀도 제한 적용된 전체 선박)
  layers.push(createShipIconLayer(ships, zoom, darkSignalIds));

  // 3. 추적 선박 레이어 (최상단 - 다른 아이콘 위에 표시)
  const trackedLayers = createTrackedShipLayers(zoom);
  if (trackedLayers.length > 0) {
    layers.push(...trackedLayers);
  }

  // 4. 선명표시 레이어들 (밀도 제한된 선박 대상 → 자체 클러스터링)
  // 아이콘이 표시되는 선박에만 라벨/신호상태 표시
  if (showLabels) {
    // 라벨 클러스터링 (밀도 제한된 ships 대상)
    const clusteredShips = getClusteredShips(ships, zoom, isIntegrate, renderTrigger);

    // 4-1. 속도벡터 레이어
    if (labelOptions.showSpeedVector) {
      const vectorLayer = createSpeedVectorLayer(clusteredShips, zoom);
      if (vectorLayer) {
        layers.push(vectorLayer);
      }
    }

    // 4-2. 선박명 레이어
    const labelLayer = createShipLabelLayer(clusteredShips, zoom, labelOptions);
    if (labelLayer) {
      layers.push(labelLayer);
    }

    // 4-3. 신호상태 레이어 (별도 클러스터링)
    if (labelOptions.showSignalStatus) {
      // 밀도 제한된 ships 대상으로 신호상태 클러스터링
      const signalClusteredShips = getSignalClusteredShips(ships, zoom, isIntegrate, renderTrigger);
      const signalLayer = createSignalStatusLayer(signalClusteredShips, zoom, isIntegrate);
      if (signalLayer) {
        layers.push(signalLayer);
      }
    }

    // 4-4. 선박크기 폴리곤 레이어 (줌 11 이상에서만)
    // 뷰포트 내 선박만 대상으로 렌더링 (성능 최적화)
    if (labelOptions.showShipSize) {
      const dimLayer = createShipDimLayer(clusteredShips, zoom);
      if (dimLayer) {
        layers.push(dimLayer);
      }
    }
  }

  return layers;
}

export default createShipLayers;
