import { ElementRef, inject } from '@angular/core';
import * as d3 from 'd3';
import { Subject } from 'rxjs';
import { datavHazardLevelColor } from '../../pages/datav/datav.utils';
import { hazardLevels } from '../../pages/manager/hazard/hazard.utils';
import { Svg, SvgGroup } from './d3.utils';
import { Station, StationD3Model } from './station.class';

export type StationEvent = {
  type: 'click';
  station: StationD3Model;
};

export class LineD3Model {
  private el = inject(ElementRef);

  svg?: Svg;
  rootGroup?: SvgGroup;
  // 添加缩放相关属性
  private readonly minZoom = 0.5;
  private readonly maxZoom = 2;
  private zoom?: d3.ZoomBehavior<SVGSVGElement, unknown>;

  // 在类的顶部添加新的属性
  private currentScale = 1;
  private readonly hoverFill = 'rgba(255, 255, 255, 0.2)';
  private readonly normalFill = 'rgba(255, 255, 255, 0.1)';
  private readonly disabledFill = 'rgba(255, 255, 255, 0.05)';

  stationMap: Record<string, StationD3Model> = {};
  stationMetaList: Station[] = [];

  stationEventSubject = new Subject<StationEvent>();

  setStationsData(data: Datav.BoardInfo) {
    const { stationTroubleIdListMap, stationRiskPointIdListMap, troubleList } = data;
    Object.entries(this.stationMap).forEach(([key, station]) => {
      station.hazardIds = stationTroubleIdListMap[key] || [];
      station.riskItemIds = stationRiskPointIdListMap[key] || [];
      if (station.hazardIds.length > 0) {
        const color = this.getHighlightColor(station.hazardIds, troubleList);
        if (color) {
          station.color = color; // 一定要放在 isShining 之前
          station.isShining = true;
        }
      }
    });
  }
  getHighlightColor(ids: number[], troubleList: Hazard.HazardDto[]) {
    const targetHazards = troubleList.filter(item => ids.includes(item.id));
    const highestLevel = hazardLevels.find(level => targetHazards.every(item => item.level === level));
    return highestLevel ? datavHazardLevelColor[highestLevel] : undefined;
  }
  initializeSvg() {
    // 创建 SVG 容器
    const svg = d3
      .select(this.el.nativeElement.querySelector('.line-airport'))
      .append('svg')
      .attr('width', '100%')
      .attr('height', '100%')
      .attr('viewBox', '0 0 1257.1 493.4')
      .attr('preserveAspectRatio', 'xMidYMid meet');

    this.renderDefs(svg);

    // 创建一个根 group 元素来包含所有地铁线路内容
    const rootGroup = svg.append('g');
    rootGroup.attr('class', 'rootGroup');

    this.svg = svg;
    this.rootGroup = rootGroup;
  }

  renderDefs(svg: Svg) {
    const defs = svg.append('defs');
    defs
      .append('radialGradient')
      .attr('cx', 0)
      .attr('cy', 0)
      .attr('r', 1)
      .attr('gradientUnits', 'userSpaceOnUse')
      .attr('id', 'gradient-opacity-simple')
      .attr('gradientTransform', 'translate(20 20) rotate(90) scale(15 15)');

    defs
      .append('radialGradient')
      .attr('cx', 0)
      .attr('cy', 0)
      .attr('r', 1)
      .attr('gradientUnits', 'userSpaceOnUse')
      .attr('id', 'gradient-opacity-complex')
      .attr('gradientTransform', 'translate(23 23) rotate(90) scale(18 18)');
  }

  // 添加缩放初始化方法
  initializeZoom() {
    if (!this.svg) return;

    this.zoom = d3
      .zoom<SVGSVGElement, unknown>()
      .filter(event => event.type !== 'dblclick')
      .scaleExtent([this.minZoom, this.maxZoom])
      .on('zoom', event => {
        this.currentScale = event.transform.k;
        this.svg!.select('g.rootGroup').attr('transform', event.transform.toString());
        this.updateZoomButtonStates();
      });

    this.svg.call(this.zoom);
    this.svg.call(this.zoom.transform, d3.zoomIdentity);
  }

  // 添加辅助方法来更新按钮状态
  private updateZoomButtonStates() {
    if (!this.svg) return;

    const zoomIn = this.svg.select('.zoom-in');
    const zoomOut = this.svg.select('.zoom-out');

    // 更新放大按钮状态
    zoomIn
      .select('rect')
      .style('fill', this.currentScale >= this.maxZoom ? this.disabledFill : this.normalFill)
      .style('cursor', this.currentScale >= this.maxZoom ? 'not-allowed' : 'pointer');

    zoomIn.select('path').style('stroke-opacity', this.currentScale >= this.maxZoom ? 0.5 : 1);

    // 更新缩小按钮状态
    zoomOut
      .select('rect')
      .style('fill', this.currentScale <= this.minZoom ? this.disabledFill : this.normalFill)
      .style('cursor', this.currentScale <= this.minZoom ? 'not-allowed' : 'pointer');

    zoomOut.select('path').style('stroke-opacity', this.currentScale <= this.minZoom ? 0.5 : 1);
  }

  renderZoomTool() {
    const toolGroup = this.svg!.append('g').attr('transform', 'translate(20, 313)');

    this.renderZoomInButton(toolGroup);
    this.renderZoomOutButton(toolGroup);
    this.renderZoomResetButton(toolGroup);
  }

  private renderZoomInButton(toolGroup: SvgGroup) {
    const zoomIn = toolGroup
      .append('g')
      .attr('class', 'zoom-in')
      .style('cursor', 'pointer')
      .on('click', (ev: Event) => {
        ev.preventDefault();
        if (this.svg && this.zoom && this.currentScale < this.maxZoom) {
          this.svg.transition().duration(300).call(this.zoom.scaleBy, 1.2);
        }
      });

    const zoomInRect = zoomIn
      .append('rect')
      .attr('x', 0)
      .attr('y', 0)
      .attr('width', 24)
      .attr('height', 24)
      .attr('rx', 2)
      .attr('style', `fill: ${this.normalFill}; stroke: #FFFFFF; stroke-width: 1px`);

    this.addHoverEffect(zoomInRect, () => this.currentScale < this.maxZoom);

    zoomIn.append('path').attr('d', 'M6,11L18,11M12,5L12,17').attr('stroke', '#FFFFFF').attr('stroke-width', '1.5');
  }

  private renderZoomOutButton(toolGroup: SvgGroup) {
    const zoomOut = toolGroup
      .append('g')
      .attr('class', 'zoom-out')
      .attr('transform', 'translate(0, 34)')
      .style('cursor', 'pointer')
      .on('click', (ev: Event) => {
        ev.preventDefault();
        if (this.svg && this.zoom && this.currentScale > this.minZoom) {
          this.svg.transition().duration(300).call(this.zoom.scaleBy, 0.8);
        }
      });

    const zoomOutRect = zoomOut
      .append('rect')
      .attr('x', 0)
      .attr('y', 0)
      .attr('width', 24)
      .attr('height', 24)
      .attr('rx', 2)
      .attr('style', `fill: ${this.normalFill}; stroke: #FFFFFF; stroke-width: 1px`);

    this.addHoverEffect(zoomOutRect, () => this.currentScale > this.minZoom);

    zoomOut.append('path').attr('d', 'M6,11L18,11').attr('stroke', '#FFFFFF').attr('stroke-width', '1.5');
  }

  private renderZoomResetButton(toolGroup: SvgGroup) {
    const zoomReset = toolGroup
      .append('g')
      .attr('class', 'zoom-reset')
      .attr('transform', 'translate(0, 67)')
      .style('cursor', 'pointer')
      .on('click', () => {
        if (this.svg && this.zoom) {
          this.svg.transition().duration(300).call(this.zoom.transform, d3.zoomIdentity);
        }
      });

    const zoomResetRect = zoomReset
      .append('rect')
      .attr('x', 0)
      .attr('y', 0)
      .attr('width', 24)
      .attr('height', 24)
      .attr('rx', 2)
      .attr('style', `fill: ${this.normalFill}; stroke: #EEEEEE; stroke-width: 1px`);

    this.addHoverEffect(zoomResetRect, () => true);

    const icon = zoomReset
      .append('path')
      .attr('class', 'zoom-reset-icon')
      .attr(
        'd',
        'M17.65 6.35A7.958 7.958 0 0012 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08A5.99 5.99 0 0112 18c-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z'
      )
      .attr('fill', '#FFFFFF')
      .attr('transform-origin', '12px 12px')
      .attr('transform', 'scale(0.8) rotate(0)');
  }

  private addHoverEffect(element: d3.Selection<SVGRectElement, unknown, null, undefined>, condition: () => boolean) {
    element
      .on('mouseover', () => {
        if (condition()) {
          element.style('fill', this.hoverFill);
        }
      })
      .on('mouseout', () => {
        if (condition()) {
          element.style('fill', this.normalFill);
        }
      });
  }

  renderStations() {
    if (!this.rootGroup) return;
    const stationsGroup = this.rootGroup.append('g');
    this.stationMetaList.forEach(rowMeta => {
      const station = new StationD3Model(rowMeta, stationsGroup, this.stationEventSubject);

      this.stationMap[station.name] = station;
    });
    this.mountStations();
  }

  mountStations() {
    Object.values(this.stationMap).forEach(station => {
      station.render();
    });
  }
}
