'use client';

import { useEffect, useRef, useState, useCallback } from 'react';
import maplibregl from 'maplibre-gl';
import type { FeatureCollection } from 'geojson';
import { Navbar } from '@/components/ui/Navbar';
import { MapControls } from '@/components/map/MapControls';
import { LayerPanel, LayerState } from '@/components/sidebar/LayerPanel';
import { relicsData, dynastyColors, categoryIcons } from '@/data/relics';

// 朝代颜色映射
const colors = dynastyColors;

// 种类形状映射（使用 MapLibre 符号图层实现不同图标）
const categories = ['painting', 'sculpture', 'bronze', 'porcelain', 'jade', 'calligraphy', 'textile', 'gold', 'lacquer', 'ceramic'];
const dynasties = Object.keys(colors);

const defaultLayerState: LayerState = {
  dynasties: Object.fromEntries(dynasties.map((d) => [d, true])),
  categories: Object.fromEntries(categories.map((c) => [c, true])),
  clusters: true,
  labels: true,
};

export function MapContainer() {
  const mapContainer = useRef<HTMLDivElement>(null);
  const map = useRef<maplibregl.Map | null>(null);
  const [layerState, setLayerState] = useState<LayerState>(defaultLayerState);
  const [loaded, setLoaded] = useState(false);

  const applyFilters = useCallback(() => {
    if (!map.current || !loaded) return;

    const visibleDynasties = dynasties.filter((d) => layerState.dynasties[d]);
    const visibleCategories = categories.filter((c) => layerState.categories[c]);

    categories.forEach((category) => {
      const layerId = `relics-${category}`;
      if (!map.current?.getLayer(layerId)) return;

      const categoryVisible = visibleCategories.includes(category);
      const visibility = categoryVisible ? 'visible' : 'none';
      map.current.setLayoutProperty(layerId, 'visibility', visibility);

      if (categoryVisible) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const filter: any = ['all', ['==', ['get', 'category'], category], ['!', ['has', 'point_count']]];
        if (visibleDynasties.length > 0 && visibleDynasties.length < dynasties.length) {
          filter.push(['match', ['get', 'dynasty'], visibleDynasties, true, false]);
        }
        map.current.setFilter(layerId, filter);
      }
    });

    ['clusters', 'cluster-count'].forEach((id) => {
      if (!map.current?.getLayer(id)) return;
      map.current.setLayoutProperty(id, 'visibility', layerState.clusters ? 'visible' : 'none');
    });
  }, [layerState, loaded]);

  useEffect(() => {
    applyFilters();
  }, [applyFilters]);

  useEffect(() => {
    if (!mapContainer.current || map.current) return;

    // 初始化地图（3D 地球模式 + 星空背景）
    // 使用 CARTO dark-matter vector 样式（与 OpenGridWorks 相同）
    map.current = new maplibregl.Map({
      container: mapContainer.current,
      style: 'https://basemaps.cartocdn.com/gl/dark-matter-nolabels-gl-style/style.json',
      center: [30, 25],
      zoom: 1.8,
      pitch: 0,
      minZoom: 0.5,
      maxZoom: 18,
      maxPitch: 85,
    });

    // 样式加载完成后设置 globe 投影和星空背景
    map.current.on('style.load', () => {
      if (!map.current) return;
      // 设置地球投影
      map.current.setProjection({ type: 'globe' });
      // 设置星空背景（纯黑太空）
      map.current.setSky({
        'sky-color': '#06060c',
        'sky-horizon-blend': 0.0,
        'horizon-color': '#06060c',
        'horizon-fog-blend': 0.0,
      });
      // 隐藏 CARTO 背景层，让星空 canvas 在太空区域透出
      if (map.current.getLayer('background')) {
        map.current.setLayoutProperty('background', 'visibility', 'none');
      }
      // 添加海洋填充层：覆盖全球的多边形，只在地球表面渲染
      // 这样海洋不透明，而太空区域仍然透明显示星空
      map.current.addSource('ocean-fill', {
        type: 'geojson',
        data: {
          type: 'Feature',
          geometry: {
            type: 'Polygon',
            coordinates: [[[-180, -85], [180, -85], [180, 85], [-180, 85], [-180, -85]]],
          },
          properties: {},
        },
      });
      // 在所有现有图层之前插入海洋填充层
      const firstLayerId = map.current.getStyle().layers[0]?.id;
      map.current.addLayer({
        id: 'ocean-fill',
        type: 'fill',
        source: 'ocean-fill',
        paint: {
          'fill-color': '#0a0e1a',
        },
      }, firstLayerId);
    });

    // 地图加载完成后添加数据
    map.current.on('load', () => {
      if (!map.current) return;

      // 添加经纬网格线（graticule）
      const graticuleData = generateGraticule(30);
      map.current.addSource('graticule', {
        type: 'geojson',
        data: graticuleData as any,
      });

      // 主要网格线（30°间隔）
      map.current.addLayer({
        id: 'graticule-main',
        type: 'line',
        source: 'graticule',
        paint: {
          'line-color': '#1e3a5f',
          'line-width': 0.8,
          'line-opacity': 0.5,
        },
      });

      // 添加更细的网格线（10°间隔）
      const fineGraticule = generateGraticule(10, 30);
      map.current.addSource('graticule-fine', {
        type: 'geojson',
        data: fineGraticule as any,
      });

      map.current.addLayer({
        id: 'graticule-fine',
        type: 'line',
        source: 'graticule-fine',
        paint: {
          'line-color': '#15294a',
          'line-width': 0.4,
          'line-opacity': 0.3,
        },
        layout: {
          'visibility': 'visible',
        },
      });

      // 网格标签
      const graticuleLabels = generateGraticuleLabels(30);
      map.current.addSource('graticule-labels', {
        type: 'geojson',
        data: graticuleLabels as any,
      });

      map.current.addLayer({
        id: 'graticule-labels',
        type: 'symbol',
        source: 'graticule-labels',
        layout: {
          'text-field': ['get', 'label'],
          'text-size': 10,
          'text-anchor': 'center',
          'text-allow-overlap': true,
          'text-font': ['Open Sans Semibold', 'Arial Unicode MS Bold'],
        },
        paint: {
          'text-color': '#3b6ea5',
          'text-opacity': 0.6,
        },
      });

      // 添加文物数据源
      map.current.addSource('relics', {
        type: 'geojson',
        data: relicsData as any,
        cluster: true,
        clusterMaxZoom: 8,
        clusterRadius: 60,
      });

      // 为每个种类添加单独的图层（不同形状）
      categories.forEach((category) => {
        // 非聚类点图层
        map.current!.addLayer({
          id: `relics-${category}`,
          type: 'symbol',
          source: 'relics',
          filter: ['all',
            ['==', ['get', 'category'], category],
            ['!', ['has', 'point_count']]
          ],
          layout: {
            'icon-image': `relic-${category}`,
            'icon-size': 1.2,
            'icon-allow-overlap': true,
            'visibility': 'visible',
          },
          paint: {
            'icon-color': [
              'case',
              ...Object.entries(colors).flatMap(([dyn, col]) => [
                ['==', ['get', 'dynasty'], dyn],
                col
              ]),
              '#888888'
            ],
          } as any // eslint-disable-line @typescript-eslint/no-explicit-any
        });
      });

      // 添加聚类图层
      map.current.addLayer({
        id: 'clusters',
        type: 'circle',
        source: 'relics',
        filter: ['has', 'point_count'],
        paint: {
          'circle-color': [
            'step',
            ['get', 'point_count'],
            '#4a5568',
            5, '#2d3748',
            10, '#1a202c',
          ],
          'circle-radius': ['step', ['get', 'point_count'], 20, 5, 28, 10, 36],
          'circle-opacity': 0.85,
          'circle-stroke-width': 2,
          'circle-stroke-color': '#a0aec0',
        },
      });

      // 聚类数量
      map.current.addLayer({
        id: 'cluster-count',
        type: 'symbol',
        source: 'relics',
        filter: ['has', 'point_count'],
        layout: {
          'text-field': '{point_count_abbreviated}',
          'text-font': ['Open Sans Bold', 'Arial Unicode MS Bold'],
          'text-size': 14,
        },
        paint: {
          'text-color': '#ffffff',
        },
      });

      // 创建自定义图标
      createRelicIcons(map.current!);
      setLoaded(true);

      // 点击聚类放大
      map.current.on('click', 'clusters', (e) => {
        if (!map.current) return;
        const features = map.current.queryRenderedFeatures(e.point, { layers: ['clusters'] });
        const clusterId = features[0].properties.cluster_id;
        (map.current.getSource('relics') as maplibregl.GeoJSONSource)
          .getClusterExpansionZoom(clusterId)
          .then((zoom) => {
            if (!map.current) return;
            map.current.easeTo({
              center: (features[0].geometry as any).coordinates,
              zoom: zoom,
            });
          });
      });

      // 点击文物显示详情
      map.current.on('click', (e) => {
        if (!map.current) return;
        const features = map.current.queryRenderedFeatures(e.point, {
          layers: categories.map(c => `relics-${c}`)
        });
        
        if (features.length === 0) return;
        
        const props = features[0].properties;
        const coordinates = (features[0].geometry as any).coordinates.slice();
        
        const name = JSON.parse(props.name);
        const museum = JSON.parse(props.museum);
        const currentLocation = JSON.parse(props.currentLocation);
        const dynastyName = getDynastyName(props.dynasty);
        const categoryName = getCategoryName(props.category);
        const color = colors[props.dynasty] || '#888888';
        const icon = categoryIcons[props.category] || '●';
        
        const html = `
          <div style="min-width: 260px; max-width: 320px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei', sans-serif; color: #f5f0e8;">
            <div style="display: flex; align-items: flex-start; gap: 10px; margin-bottom: 10px;">
              <div style="display: flex; align-items: center; justify-content: center; width: 38px; height: 38px; border-radius: 50%; background: linear-gradient(135deg, ${color}22, ${color}44); border: 1px solid ${color}66; flex-shrink: 0;">
                <span style="font-size: 20px; filter: drop-shadow(0 1px 2px rgba(0,0,0,0.4));">${icon}</span>
              </div>
              <div style="flex: 1; min-width: 0;">
                <h3 style="margin: 0 0 4px 0; font-size: 17px; font-weight: 600; color: #faf6ef; letter-spacing: 0.04em; line-height: 1.3;">${name.zh}</h3>
                <p style="margin: 0; font-size: 12px; color: #b0a89a; font-style: italic; letter-spacing: 0.02em;">${name.en}</p>
              </div>
            </div>
            <div style="display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px;">
              <span style="background: ${color}33; color: ${color}; border: 1px solid ${color}66; padding: 3px 10px; border-radius: 12px; font-size: 12px; font-weight: 500;">${dynastyName}</span>
              <span style="background: rgba(251, 191, 36, 0.12); color: #fbbf24; border: 1px solid rgba(251, 191, 36, 0.35); padding: 3px 10px; border-radius: 12px; font-size: 12px; font-weight: 500;">${categoryName}</span>
            </div>
            <div style="border-top: 1px solid rgba(255, 255, 255, 0.1); padding-top: 10px; font-size: 13px; color: #d9d0c3; line-height: 1.7;">
              <p style="margin: 5px 0; display: flex; gap: 6px;">
                <span style="color: #a89a88; flex-shrink: 0;">收藏地</span>
                <span style="color: #f5f0e8;">${currentLocation.zh}</span>
              </p>
              <p style="margin: 5px 0; display: flex; gap: 6px;">
                <span style="color: #a89a88; flex-shrink: 0;">机构</span>
                <span style="color: #f5f0e8;">${museum.zh}</span>
              </p>
              ${props.year ? `<p style="margin: 5px 0; display: flex; gap: 6px;"><span style="color: #a89a88; flex-shrink: 0;">年代</span><span style="color: #f5f0e8;">${props.year}</span></p>` : ''}
            </div>
          </div>
        `;

        new maplibregl.Popup({ offset: 28, closeButton: true, maxWidth: '340px', className: 'heritage-popup' })
          .setLngLat(coordinates)
          .setHTML(html)
          .addTo(map.current);
      });

      // 鼠标样式
      categories.forEach(cat => {
        map.current!.on('mouseenter', `relics-${cat}`, () => {
          if (map.current) map.current.getCanvas().style.cursor = 'pointer';
        });
        map.current!.on('mouseleave', `relics-${cat}`, () => {
          if (map.current) map.current.getCanvas().style.cursor = '';
        });
      });

      map.current.on('mouseenter', 'clusters', () => {
        if (map.current) map.current.getCanvas().style.cursor = 'pointer';
      });
      map.current.on('mouseleave', 'clusters', () => {
        if (map.current) map.current.getCanvas().style.cursor = '';
      });
    });

    return () => {
      if (map.current) {
        map.current.remove();
        map.current = null;
      }
    };
  }, []);

  const handleZoomIn = () => map.current?.zoomIn();
  const handleZoomOut = () => map.current?.zoomOut();
  const handleLocate = () => {
    if (!map.current) return;
    navigator.geolocation?.getCurrentPosition(
      (pos) => {
        map.current?.flyTo({
          center: [pos.coords.longitude, pos.coords.latitude],
          zoom: 5,
        });
      },
      () => {
        map.current?.flyTo({ center: [105, 35], zoom: 4 });
      }
    );
  };
  const handleSpotlight = () => {
    // Placeholder: could enable circle selection mode
    if (!map.current) return;
    map.current.getCanvas().style.cursor = 'crosshair';
    setTimeout(() => {
      if (map.current) map.current.getCanvas().style.cursor = '';
    }, 3000);
  };
  const handleSearch = (query: string) => {
    if (!map.current) return;
    const features = (relicsData as any).features;
    const match = features.find((f: any) => {
      const name = f.properties.name;
      return (
        name.zh.includes(query) ||
        name.en.toLowerCase().includes(query.toLowerCase()) ||
        f.properties.museum.zh.includes(query) ||
        f.properties.museum.en.toLowerCase().includes(query.toLowerCase())
      );
    });
    if (match) {
      map.current.flyTo({
        center: match.geometry.coordinates,
        zoom: 8,
      });
    }
  };
  const handleReset = () => setLayerState(defaultLayerState);

  return (
    <div className="relative w-full h-full">
      <Starfield />
      <Navbar />
      <MapControls
        onSearch={handleSearch}
        onZoomIn={handleZoomIn}
        onZoomOut={handleZoomOut}
        onLocate={handleLocate}
        onSpotlight={handleSpotlight}
      />
      <LayerPanel state={layerState} onChange={setLayerState} onReset={handleReset} />
      <div ref={mapContainer} className="w-full h-full relative z-0" />
    </div>
  );
}

// 动态星空背景组件
function Starfield() {
  const canvasRef = useRef<HTMLCanvasElement>(null);

  useEffect(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    if (!ctx) return;

    let animationId: number;
    let running = true;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    let stars: any[] = [];
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    let shootingStars: any[] = [];

    // 按颜色分组，减少 fillStyle 切换
    const colorGroups = [
      { rgb: '255, 255, 255', indices: [] as number[] },
      { rgb: '200, 220, 255', indices: [] as number[] },
      { rgb: '255, 240, 200', indices: [] as number[] },
      { rgb: '220, 230, 255', indices: [] as number[] },
    ];

    const resize = () => {
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
      const count = Math.floor((canvas.width * canvas.height) / 3500);
      colorGroups.forEach(g => g.indices = []);
      stars = Array.from({ length: count }, (_, i) => {
        const ci = Math.floor(Math.random() * colorGroups.length);
        colorGroups[ci].indices.push(i);
        return {
          x: Math.random() * canvas.width,
          y: Math.random() * canvas.height,
          r: Math.random() * 1.5 + 0.3,
          baseOpacity: Math.random() * 0.7 + 0.3,
          twinkleSpeed: Math.random() * 0.04 + 0.01,
          twinklePhase: Math.random() * Math.PI * 2,
          vx: (Math.random() - 0.5) * 0.03,
          vy: (Math.random() - 0.5) * 0.03,
          ci,
        };
      });
    };

    resize();
    window.addEventListener('resize', resize);

    // 标签页隐藏时暂停动画
    const onVisibility = () => {
      if (document.hidden) {
        running = false;
        if (animationId) cancelAnimationFrame(animationId);
      } else if (!running) {
        running = true;
        render();
      }
    };
    document.addEventListener('visibilitychange', onVisibility);

    let frame = 0;

    const render = () => {
      if (!running) return;
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      // 按颜色分组绘制星星，减少 fillStyle 切换
      for (const group of colorGroups) {
        ctx.fillStyle = `rgba(${group.rgb}, 1)`;
        for (const i of group.indices) {
          const star = stars[i];
          star.twinklePhase += star.twinkleSpeed;
          star.x += star.vx;
          star.y += star.vy;
          if (star.x < 0) star.x = canvas.width;
          if (star.x > canvas.width) star.x = 0;
          if (star.y < 0) star.y = canvas.height;
          if (star.y > canvas.height) star.y = 0;

          const alpha = star.baseOpacity * (0.2 + 0.8 * (0.5 + 0.5 * Math.sin(star.twinklePhase)));
          ctx.globalAlpha = alpha;
          ctx.beginPath();
          ctx.arc(star.x, star.y, star.r, 0, Math.PI * 2);
          ctx.fill();

          if (star.r > 1.0) {
            ctx.globalAlpha = alpha * 0.15;
            ctx.beginPath();
            ctx.arc(star.x, star.y, star.r * 2.5, 0, Math.PI * 2);
            ctx.fill();
          }
        }
      }
      ctx.globalAlpha = 1;

      // 随机生成流星
      frame++;
      if (frame % 200 === 0 && Math.random() < 0.7) {
        const startX = Math.random() * canvas.width;
        const startY = Math.random() * canvas.height * 0.5;
        const angle = Math.PI / 4 + (Math.random() - 0.5) * 0.3;
        const speed = 8 + Math.random() * 6;
        shootingStars.push({
          x: startX,
          y: startY,
          vx: Math.cos(angle) * speed,
          vy: Math.sin(angle) * speed,
          life: 0,
          maxLife: 40 + Math.random() * 20,
          length: 80 + Math.random() * 60,
        });
      }

      // 绘制流星
      shootingStars = shootingStars.filter(s => s.life < s.maxLife);
      for (const s of shootingStars) {
        s.life++;
        s.x += s.vx;
        s.y += s.vy;
        const progress = s.life / s.maxLife;
        const alpha = progress < 0.3 ? progress / 0.3 : 1 - (progress - 0.3) / 0.7;

        const tailX = s.x - s.vx / Math.hypot(s.vx, s.vy) * s.length;
        const tailY = s.y - s.vy / Math.hypot(s.vx, s.vy) * s.length;

        const gradient = ctx.createLinearGradient(s.x, s.y, tailX, tailY);
        gradient.addColorStop(0, `rgba(255, 255, 255, ${alpha})`);
        gradient.addColorStop(0.5, `rgba(200, 220, 255, ${alpha * 0.5})`);
        gradient.addColorStop(1, 'rgba(200, 220, 255, 0)');

        ctx.beginPath();
        ctx.moveTo(s.x, s.y);
        ctx.lineTo(tailX, tailY);
        ctx.strokeStyle = gradient;
        ctx.lineWidth = 1.5;
        ctx.stroke();

        ctx.beginPath();
        ctx.arc(s.x, s.y, 1.5, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(255, 255, 255, ${alpha})`;
        ctx.fill();
      }

      animationId = requestAnimationFrame(render);
    };

    render();

    return () => {
      running = false;
      if (animationId) cancelAnimationFrame(animationId);
      window.removeEventListener('resize', resize);
      document.removeEventListener('visibilitychange', onVisibility);
    };
  }, []);

  return (
    <canvas
      ref={canvasRef}
      className="absolute inset-0 z-0 pointer-events-none"
      style={{ background: '#06060c', willChange: 'transform' }}
    />
  );
}

// 生成经纬网格线 GeoJSON
function generateGraticule(interval: number, skipMultiples?: number): FeatureCollection {
  const features: any[] = [];
  const skip = skipMultiples || 0;

  // 经线 (meridians)
  for (let lon = -180; lon <= 180; lon += interval) {
    if (skip > 0 && lon % skip === 0) continue;
    const coords: [number, number][] = [];
    for (let lat = -85; lat <= 85; lat += 5) {
      coords.push([lon, lat]);
    }
    features.push({
      type: 'Feature',
      geometry: { type: 'LineString', coordinates: coords },
      properties: { type: 'meridian', value: lon },
    });
  }

  // 纬线 (parallels)
  for (let lat = -80; lat <= 80; lat += interval) {
    if (skip > 0 && lat % skip === 0) continue;
    const coords: [number, number][] = [];
    for (let lon = -180; lon <= 180; lon += 5) {
      coords.push([lon, lat]);
    }
    features.push({
      type: 'Feature',
      geometry: { type: 'LineString', coordinates: coords },
      properties: { type: 'parallel', value: lat },
    });
  }

  return { type: 'FeatureCollection', features };
}

// 生成网格标签 GeoJSON
function generateGraticuleLabels(interval: number): FeatureCollection {
  const features: any[] = [];

  // 经度标签（赤道附近）
  for (let lon = -180; lon <= 180; lon += interval) {
    features.push({
      type: 'Feature',
      geometry: { type: 'Point', coordinates: [lon, 0] },
      properties: {
        label: lon === 0 ? '0°' : lon > 0 ? `${lon}°E` : `${Math.abs(lon)}°W`,
      },
    });
  }

  // 纬度标签（本初子午线附近）
  for (let lat = -60; lat <= 60; lat += interval) {
    if (lat === 0) continue;
    features.push({
      type: 'Feature',
      geometry: { type: 'Point', coordinates: [0, lat] },
      properties: {
        label: lat > 0 ? `${lat}°N` : `${Math.abs(lat)}°S`,
      },
    });
  }

  return { type: 'FeatureCollection', features };
}

// 种类名称映射
function getCategoryName(category: string): string {
  const names: Record<string, string> = {
    painting: '书画', sculpture: '雕塑', bronze: '青铜', porcelain: '瓷器',
    jade: '玉器', calligraphy: '书法', textile: '织物', gold: '金银',
    lacquer: '漆器', ceramic: '陶器'
  };
  return names[category] || category;
}

// 朝代名称映射
function getDynastyName(dynasty: string): string {
  const names: Record<string, string> = {
    shang: '商', zhou: '周', qin: '秦', han: '汉',
    tang: '唐', song: '宋', yuan: '元', ming: '明', qing: '清'
  };
  return names[dynasty] || dynasty;
}

// 创建自定义图标
function createRelicIcons(map: maplibregl.Map) {
  const size = 40;
  
  // 为每个种类创建不同形状的图标
  categories.forEach(category => {
    const canvas = document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;
    const ctx = canvas.getContext('2d')!;
    
    ctx.fillStyle = '#ffffff';
    ctx.strokeStyle = '#000000';
    ctx.lineWidth = 2;
    
    switch (category) {
      case 'painting': // 方块
        ctx.fillRect(8, 8, 24, 24);
        ctx.strokeRect(8, 8, 24, 24);
        break;
      case 'sculpture': // 三角
        ctx.beginPath();
        ctx.moveTo(20, 6);
        ctx.lineTo(34, 34);
        ctx.lineTo(6, 34);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
        break;
      case 'bronze': // 菱形
        ctx.beginPath();
        ctx.moveTo(20, 4);
        ctx.lineTo(36, 20);
        ctx.lineTo(20, 36);
        ctx.lineTo(4, 20);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();
        break;
      case 'porcelain': // 圆点
        ctx.beginPath();
        ctx.arc(20, 20, 14, 0, Math.PI * 2);
        ctx.fill();
        ctx.stroke();
        break;
      case 'jade': // 六边形
        drawHexagon(ctx, 20, 20, 14);
        ctx.fill();
        ctx.stroke();
        break;
      case 'calligraphy': // 星形
        drawStar(ctx, 20, 20, 5, 14, 7);
        ctx.fill();
        ctx.stroke();
        break;
      case 'textile': // 菱星
        drawDiamondStar(ctx, 20, 20, 12);
        ctx.fill();
        ctx.stroke();
        break;
      case 'gold': // 八边
        drawOctagon(ctx, 20, 20, 14);
        ctx.fill();
        ctx.stroke();
        break;
      case 'lacquer': // 双菱
        drawDoubleDiamond(ctx, 20, 20, 12);
        ctx.fill();
        ctx.stroke();
        break;
      case 'ceramic': // 空心圆
        ctx.beginPath();
        ctx.arc(20, 20, 14, 0, Math.PI * 2);
        ctx.stroke();
        break;
    }
    
    const imageData = ctx.getImageData(0, 0, size, size);
    map.addImage(`relic-${category}`, { width: size, height: size, data: imageData.data as any });
  });
}

function drawHexagon(ctx: CanvasRenderingContext2D, cx: number, cy: number, r: number) {
  ctx.beginPath();
  for (let i = 0; i < 6; i++) {
    const angle = (Math.PI / 3) * i - Math.PI / 2;
    const x = cx + r * Math.cos(angle);
    const y = cy + r * Math.sin(angle);
    if (i === 0) ctx.moveTo(x, y);
    else ctx.lineTo(x, y);
  }
  ctx.closePath();
}

function drawStar(ctx: CanvasRenderingContext2D, cx: number, cy: number, points: number, outer: number, inner: number) {
  ctx.beginPath();
  for (let i = 0; i < points * 2; i++) {
    const r = i % 2 === 0 ? outer : inner;
    const angle = (Math.PI / points) * i - Math.PI / 2;
    const x = cx + r * Math.cos(angle);
    const y = cy + r * Math.sin(angle);
    if (i === 0) ctx.moveTo(x, y);
    else ctx.lineTo(x, y);
  }
  ctx.closePath();
}

function drawDiamondStar(ctx: CanvasRenderingContext2D, cx: number, cy: number, r: number) {
  ctx.beginPath();
  ctx.moveTo(cx, cy - r);
  ctx.lineTo(cx + r, cy);
  ctx.lineTo(cx, cy + r);
  ctx.lineTo(cx - r, cy);
  ctx.closePath();
  ctx.moveTo(cx, cy - r * 0.6);
  ctx.lineTo(cx + r * 0.6, cy);
  ctx.lineTo(cx, cy + r * 0.6);
  ctx.lineTo(cx - r * 0.6, cy);
  ctx.closePath();
}

function drawOctagon(ctx: CanvasRenderingContext2D, cx: number, cy: number, r: number) {
  ctx.beginPath();
  for (let i = 0; i < 8; i++) {
    const angle = (Math.PI / 4) * i - Math.PI / 8;
    const x = cx + r * Math.cos(angle);
    const y = cy + r * Math.sin(angle);
    if (i === 0) ctx.moveTo(x, y);
    else ctx.lineTo(x, y);
  }
  ctx.closePath();
}

function drawDoubleDiamond(ctx: CanvasRenderingContext2D, cx: number, cy: number, r: number) {
  ctx.beginPath();
  ctx.moveTo(cx, cy - r);
  ctx.lineTo(cx + r * 0.7, cy);
  ctx.lineTo(cx, cy + r);
  ctx.lineTo(cx - r * 0.7, cy);
  ctx.closePath();
  ctx.strokeRect(cx - r * 0.5, cy - r * 0.5, r, r);
}