import { Component, Inject, OnDestroy, OnInit, ViewChild, ElementRef } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import * as echarts from 'echarts';
import { FmodeObject, FmodeQuery, FmodeParse } from 'fmode-ng/parse';
const Parse = FmodeParse.with('nova');

export interface ProjectFileLike {
  id?: string;
  name?: string;
  originalName?: string;
  url: string;
  type?: string;
  size?: number;
}

interface PaletteColor {
  rgb: { r: number; g: number; b: number };
  hex: string;
  percentage: number;
}

interface ColorAnalysisReport {
  palette: PaletteColor[];
  mosaicUrl?: string;
  metrics: {
    warmCoolBalance: number; // -100(冷) 到 100(暖)
    averageBrightness: number; // 0-100
    averageSaturation: number; // 0-100
    diversity: number; // 色彩多样度：主色数量
  };
  histogram: {
    brightnessBins: number[]; // 0..100
    saturationBins: number[]; // 0..100
  };
  splitPoints: Array<{ temp: number; brightness: number; size: number; color: string }>;
}

@Component({
  selector: 'app-color-get-dialog',
  standalone: true,
  imports: [CommonModule, MatDialogModule],
  templateUrl: './color-get-dialog.component.html',
  styleUrls: ['./color-get-dialog.component.scss']
})
export class ColorGetDialogComponent implements OnInit, OnDestroy {
  @ViewChild('mosaicCanvas') mosaicCanvasRef!: ElementRef<HTMLCanvasElement>;
  @ViewChild('histogramChart') histogramChartRef!: ElementRef<HTMLDivElement>;
  @ViewChild('splitChart') splitChartRef!: ElementRef<HTMLDivElement>;

  imageUrl = '';
  imageName = '';
  imageSize?: number;
  loading = true;
  progress = 0;

  pixelSize = 100; // 参考图马赛克像素块大小
  report?: ColorAnalysisReport;

  private histogramChart?: echarts.ECharts;
  private splitChart?: echarts.ECharts;

  fileObject?: FmodeObject;
  saving = false;
  saveMessage = '';

  constructor(
    private dialogRef: MatDialogRef<ColorGetDialogComponent>,
    @Inject(MAT_DIALOG_DATA) public data: { file?: ProjectFileLike; fileObject?: FmodeObject; fileId?: string; url?: string; name?: string }
  ) {}

  async ngOnInit(): Promise<void> {
    const file = this.data?.file;
    this.imageUrl = file?.url || this.data?.url || '';
    this.imageName = file?.originalName || file?.name || this.data?.name || '未命名图片';
    this.imageSize = file?.size;

    // 解析文件对象
    this.fileObject = this.data?.fileObject || await this.fetchFileObjectById(file?.id || this.data?.fileId);
    if (this.fileObject) {
      const urlFromObj = (this.fileObject.get('url') || this.fileObject.get('fileUrl')) as string | undefined;
      if (!this.imageUrl && urlFromObj) this.imageUrl = urlFromObj;

      const loaded = await this.tryLoadExistingAnalysis();
      if (loaded) {
        return;
      }
    }

    if (!this.imageUrl) {
      this.loading = false;
      return;
    }

    // 开始分析
    this.loadAndAnalyze(this.imageUrl).catch(err => {
      console.error('色彩分析失败:', err);
      this.loading = false;
    });
  }

  ngOnDestroy(): void {
    if (this.histogramChart) {
      this.histogramChart.dispose();
    }
    if (this.splitChart) {
      this.splitChart.dispose();
    }
  }

  close(): void {
    this.dialogRef.close();
  }

  private async loadAndAnalyze(url: string): Promise<void> {
    this.progress = 5;
    const img = await this.loadImage(url);
    this.progress = 20;

    const { mosaicCanvas, blockColors } = this.createMosaic(img, this.pixelSize);
    this.progress = 50;

    // 显示马赛克图
    const canvas = this.mosaicCanvasRef.nativeElement;
    canvas.width = mosaicCanvas.width;
    canvas.height = mosaicCanvas.height;
    const ctx = canvas.getContext('2d');
    if (ctx) ctx.drawImage(mosaicCanvas, 0, 0);

    // 构建色彩报告
    this.report = this.buildReport(blockColors);
    this.progress = 80;

    // 渲染图表
    setTimeout(() => {
      this.renderHistogram();
      this.renderSplitChart();
      this.progress = 100;
      this.loading = false;
    }, 0);
  }

  private loadImage(url: string): Promise<HTMLImageElement> {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.crossOrigin = 'anonymous';
      img.onload = () => resolve(img);
      img.onerror = reject;
      img.src = url;
    });
  }

  private createMosaic(image: HTMLImageElement, pixelSize: number): { mosaicCanvas: HTMLCanvasElement; blockColors: { r: number; g: number; b: number }[] } {
    const width = image.width;
    const height = image.height;
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d')!;
    ctx.drawImage(image, 0, 0, width, height);

    const blockColors: { r: number; g: number; b: number }[] = [];

    for (let y = 0; y < height; y += pixelSize) {
      for (let x = 0; x < width; x += pixelSize) {
        const bw = Math.min(pixelSize, width - x);
        const bh = Math.min(pixelSize, height - y);
        const data = ctx.getImageData(x, y, bw, bh).data;

        let r = 0, g = 0, b = 0;
        const count = bw * bh;
        for (let i = 0; i < data.length; i += 4) {
          r += data[i];
          g += data[i + 1];
          b += data[i + 2];
        }
        r = Math.round(r / count);
        g = Math.round(g / count);
        b = Math.round(b / count);

        blockColors.push({ r, g, b });

        ctx.fillStyle = `rgb(${r},${g},${b})`;
        ctx.fillRect(x, y, bw, bh);
      }
    }

    return { mosaicCanvas: canvas, blockColors };
  }

  private buildReport(blockColors: { r: number; g: number; b: number }[]): ColorAnalysisReport {
    // 统计颜色频率
    const colorMap = new Map<string, number>();
    const totalBlocks = blockColors.length;

    blockColors.forEach(({ r, g, b }) => {
      const key = `${r},${g},${b}`; // 精确块平均色
      colorMap.set(key, (colorMap.get(key) || 0) + 1);
    });

    // 合并近似色（降低抖动），按 16 级量化
    const quantMap = new Map<string, number>();
    colorMap.forEach((count, key) => {
      const [r, g, b] = key.split(',').map(Number);
      const qr = Math.round(r / 16) * 16;
      const qg = Math.round(g / 16) * 16;
      const qb = Math.round(b / 16) * 16;
      const qkey = `${qr},${qg},${qb}`;
      quantMap.set(qkey, (quantMap.get(qkey) || 0) + count);
    });

    const palette = Array.from(quantMap.entries())
      .map(([k, c]) => {
        const [r, g, b] = k.split(',').map(Number);
        const hex = this.rgbToHex(r, g, b);
        return {
          rgb: { r, g, b },
          hex,
          percentage: +(c / totalBlocks * 100).toFixed(2)
        } as PaletteColor;
      })
      .sort((a, b) => b.percentage - a.percentage)
      .slice(0, 20);

    // 计算指标与分布
    const brightnessBins = new Array(10).fill(0); // 10等分
    const saturationBins = new Array(10).fill(0);
    let sumBrightness = 0;
    let sumSaturation = 0;
    let sumTempScore = 0;

    const splitPoints: Array<{ temp: number; brightness: number; size: number; color: string }> = [];

    blockColors.forEach(({ r, g, b }) => {
      const { h, s, v } = this.rgbToHsv(r, g, b);
      const brightness = v * 100;
      const saturation = s * 100;
      const temp = this.warmCoolScoreFromHue(h); // -100..100

      sumBrightness += brightness;
      sumSaturation += saturation;
      sumTempScore += temp;

      const bIdx = Math.min(9, Math.floor(brightness / 10));
      const sIdx = Math.min(9, Math.floor(saturation / 10));
      brightnessBins[bIdx]++;
      saturationBins[sIdx]++;

      splitPoints.push({ temp, brightness, size: 1, color: `rgb(${r},${g},${b})` });
    });

    const avgBrightness = +(sumBrightness / totalBlocks).toFixed(1);
    const avgSaturation = +(sumSaturation / totalBlocks).toFixed(1);
    const warmCoolBalance = +((sumTempScore / totalBlocks)).toFixed(1);

    return {
      palette,
      metrics: {
        warmCoolBalance,
        averageBrightness: avgBrightness,
        averageSaturation: avgSaturation,
        diversity: palette.length
      },
      histogram: {
        brightnessBins: brightnessBins.map(v => Math.round(v)),
        saturationBins: saturationBins.map(v => Math.round(v))
      },
      splitPoints
    };
  }

  private renderHistogram(): void {
    if (!this.report) return;
    const el = this.histogramChartRef.nativeElement;
    this.histogramChart = echarts.init(el);

    const option: echarts.EChartsOption = {
      tooltip: {},
      grid: { left: 40, right: 20, top: 30, bottom: 40 },
      legend: { data: ['亮度', '饱和度'] },
      xAxis: {
        type: 'category',
        data: ['0-10', '10-20', '20-30', '30-40', '40-50', '50-60', '60-70', '70-80', '80-90', '90-100']
      },
      yAxis: { type: 'value' },
      series: [
        {
          name: '亮度',
          type: 'bar',
          data: this.report.histogram.brightnessBins,
          itemStyle: { color: '#4ECDC4' }
        },
        {
          name: '饱和度',
          type: 'bar',
          data: this.report.histogram.saturationBins,
          itemStyle: { color: '#FF6B6B' }
        }
      ]
    };

    this.histogramChart.setOption(option);
  }

  private renderSplitChart(): void {
    if (!this.report) return;
    const el = this.splitChartRef.nativeElement;
    this.splitChart = echarts.init(el);

    const data = this.report.splitPoints.map(p => [p.temp, p.brightness, p.size, p.color]);

    const option: echarts.EChartsOption = {
      tooltip: {
        formatter: (params: any) => {
          const [temp, bright, , color] = params.data;
          return `冷暖: ${temp.toFixed(1)}<br/>亮度: ${bright.toFixed(1)}<br/><span style="display:inline-block;width:12px;height:12px;background:${color};margin-right:6px"></span>${color}`;
        }
      },
      xAxis: {
        type: 'value',
        min: -100,
        max: 100,
        name: '冷 ← → 暖'
      },
      yAxis: {
        type: 'value',
        min: 0,
        max: 100,
        name: '暗 ↑ ↓ 亮'
      },
      series: [
        {
          name: '色彩拆分',
          type: 'scatter',
          symbolSize: 8,
          data,
          itemStyle: {
            color: (p: any) => p.data[3]
          }
        }
      ]
    };

    this.splitChart.setOption(option);
  }

  // --- 色彩工具函数 ---
  private rgbToHex(r: number, g: number, b: number): string {
    const toHex = (n: number) => n.toString(16).padStart(2, '0');
    return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
  }

  private rgbToHsv(r: number, g: number, b: number): { h: number; s: number; v: number } {
    r /= 255; g /= 255; b /= 255;
    const max = Math.max(r, g, b), min = Math.min(r, g, b);
    const v = max;
    const d = max - min;
    const s = max === 0 ? 0 : d / max;
    let h = 0;
    if (max === min) {
      h = 0;
    } else {
      switch (max) {
        case r: h = (g - b) / d + (g < b ? 6 : 0); break;
        case g: h = (b - r) / d + 2; break;
        case b: h = (r - g) / d + 4; break;
      }
      h /= 6;
    }
    return { h: h * 360, s, v };
  }

  private warmCoolScoreFromHue(hue: number): number {
    // 简化冷暖评分：红橙黄(0-60)与洋红(300-360)偏暖；青蓝紫(180-300)偏冷；绿色(60-180)中性略冷
    if (hue >= 0 && hue < 60) return 80 - (60 - hue) * (80 / 60); // 80→0
    if (hue >= 60 && hue < 120) return 20 - (120 - hue) * (20 / 60); // 20→0
    if (hue >= 120 && hue < 180) return -20 + (hue - 120) * (20 / 60); // -20→0
    if (hue >= 180 && hue < 240) return -60 + (hue - 180) * (40 / 60); // -60→-20
    if (hue >= 240 && hue < 300) return -80 + (hue - 240) * (20 / 60); // -80→-60
    if (hue >= 300 && hue <= 360) return 80 - (360 - hue) * (80 / 60); // 80→0
    return 0;
  }

  private async fetchFileObjectById(id?: string): Promise<FmodeObject | undefined> {
    if (!id) return undefined;
    try {
      const query = new FmodeQuery('ProjectFile');
      const obj = await query.get(id);
      return obj;
    } catch (e) {
      console.error('获取文件对象失败:', e);
      return undefined;
    }
  }

  private async tryLoadExistingAnalysis(): Promise<boolean> {
    try {
      const existing = this.fileObject?.get('analysis')?.color as any;
      if (existing) {
        this.report = existing;
        this.loading = false;
        setTimeout(() => {
          this.renderHistogram();
          this.renderSplitChart();
        }, 0);
        return true;
      }
    } catch (e) {
      console.warn('读取已有色彩分析失败或不存在:', e);
    }
    return false;
  }

  async saveAnalysis(): Promise<void> {
    if (!this.report) return;
    this.saving = true;
    this.saveMessage = '';
    try {
      let obj = this.fileObject;
      if (!obj) {
        obj = await this.fetchFileObjectById(this.data?.file?.id || this.data?.fileId);
      }
      if (!obj) throw new Error('无法定位文件对象，保存失败');

      const current = obj.get('analysis') || {};
      current.color = {
        ...this.report,
        version: '1.0',
        pixelSize: this.pixelSize,
        source: 'color-get',
        createdAt: new Date().toISOString()
      };
      obj.set('analysis', current);
      await obj.save();
      this.fileObject = obj;
      this.saveMessage = '已保存色彩分析';
    } catch (e) {
      console.error('保存色彩分析失败:', e);
      this.saveMessage = '保存失败';
    } finally {
      this.saving = false;
    }
  }

  async reAnalyze(): Promise<void> {
    if (!this.imageUrl) return;

    // 重新分析前清理现有图表与画布，避免内存泄漏与残留数据
    if (this.histogramChart) {
      this.histogramChart.dispose();
      this.histogramChart = undefined;
    }
    if (this.splitChart) {
      this.splitChart.dispose();
      this.splitChart = undefined;
    }

    const mosaicCanvasEl = this.mosaicCanvasRef?.nativeElement;
    if (mosaicCanvasEl) {
      const ctx = mosaicCanvasEl.getContext('2d');
      if (ctx) {
        ctx.clearRect(0, 0, mosaicCanvasEl.width, mosaicCanvasEl.height);
      }
    }

    this.loading = true;
    this.progress = 0;
    this.report = undefined;

    try {
      await this.loadAndAnalyze(this.imageUrl);
    } catch (err) {
      console.error('重新分析失败:', err);
      this.loading = false;
    }
  }
}