import {AfterViewInit, Component, Input, OnInit} from '@angular/core';

import {select} from 'd3';

import {DiscsChartBaseService} from './discs-chart-base.service';
import {SdmDihService} from '../sdm-dih.service';

/**
 * Universal component representing one disc in any disc-chart
 */
@Component({
  // eslint-disable-next-line @angular-eslint/component-selector
  selector: 'disc',
  templateUrl: 'disc.component.html',
})
export class DiscComponent implements OnInit, AfterViewInit {
  @Input() region: string;
  /**
   * TODO: useless? scenario is unique and contains domain per se
   */
  @Input() domain = 'baseline';
  @Input() factor = 'aggregated';
  /**
   * Switch whether the disc input properties shall be updated when new time is selected.
   * Used for scenario comparison graphs.
   */
  @Input() inSitu = false;
  @Input() scenario = 'baseline';
  @Input() show: 'name' | 'factor' | 'scenario' = 'name';
  /**
   * A unique ID for a DIV element in which the disc will be drawn.
   * Constructed from [region, scenario, factor, nonce] tuple, where nonce is a random series of numbers
   */
  divId = 'graph-place';
  /**
   * Pointer to <use> SVG element of an arrow in this disc
   */
  private arrowUse;
  /**
   * Attractiveness data about a region this disc represents
   */
  private regionData;
  /**
   * Pointer to <g> SVG element of the main area of this disc
   */
  private svgContent;
  /**
   * Pointer to <text> SVG element of the text above this disc
   */
  private svgContentText;

  constructor(
    public sdmDihService: SdmDihService,
    public yearGraphService: DiscsChartBaseService
  ) {}

  ngOnInit(): void {
    const regionSafeName = this.region.replaceAll(' ', '_');
    const scenarioSafeName = this.scenario.replaceAll(' ', '_');
    const factorSafeName = this.factor.split('/').pop();
    const nonce = Math.round(Math.random() * 10000) + '';
    this.divId = `graph-place-${regionSafeName}-${scenarioSafeName}-${factorSafeName}-${nonce}`;
  }

  ngAfterViewInit(): void {
    this.sdmDihService.dataLoads.subscribe((loaded) => {
      if (!loaded) {
        return;
      }
      this.drawGraph();
    });
    this.yearGraphService.graphRefreshes.subscribe(({region, domain}) => {
      if (this.inSitu && region) {
        this.region = region;
      }
      if (this.inSitu && domain) {
        this.domain = domain;
      }
      this.updateGraph();
    });
  }

  drawGraph(): void {
    const year = this.yearGraphService.selectedYear.toString().includes('.')
      ? this.yearGraphService.selectedYear
      : this.yearGraphService.selectedYear + '.0';
    this.regionData = this.sdmDihService.sdmData[year].find(
      (row) => row['MODEL'] === this.region && row['SCENARIO'] === this.scenario
    );
    /* When the parent element has position "flex", this can be set to 100% */
    const width = 100; // / this.sdmDihService.regions.length;
    const height = 100; // / this.sdmDihService.regions.length;
    /* append the svg object to the div called 'graph-place-...' */
    const svg = select(`#${this.divId}`)
      .append('svg')
      .attr('width', `${width}%`)
      .attr('height', `${height}%`)
      .append('svg')
      .attr('x', '50%')
      .attr('y', '50%')
      .attr('overflow', 'visible');
    // arrow symbol for later re-use
    const arrow = svg.append('symbol').attr('id', 'arrow');
    // horizontal line
    arrow
      .append('line')
      .attr('x1', 0)
      .attr('y1', 30)
      .attr('x2', 60)
      .attr('y2', 30)
      .attr('stroke', 'black')
      .style('stroke-width', 4);
    // upper line
    arrow
      .append('line')
      .attr('x1', 40)
      .attr('y1', 10)
      .attr('x2', 60)
      .attr('y2', 30)
      .attr('stroke', 'black')
      .style('stroke-width', 4);
    // bottom line
    arrow
      .append('line')
      .attr('x1', 40)
      .attr('y1', 50)
      .attr('x2', 60)
      .attr('y2', 30)
      .attr('stroke', 'black')
      .style('stroke-width', 4);
    this.svgContent = svg.append('g');
    this.svgContent.data(() => [this.regionData]);
    //.attr('transform', 'translate(' + width / 2 + '% ,' + height / 2 + '% )');
    this.svgContent
      .append('circle')
      .attr('cx', 0)
      .attr('cy', 0)
      .attr('r', 50)
      .attr('stroke', 'black')
      .attr('fill', (d) => {
        return this.sdmDihService.perc2color(
          d[this.factor]?.index ?? d[this.factor]
        );
      });
    this.svgContent
      .append('text')
      .attr('x', 0)
      .attr('y', -60)
      .attr('dy', '.35em')
      .text((d) => {
        switch (this.show) {
          case 'factor':
            return this.factor.split('/').pop();
          case 'scenario':
            return this.scenario;
          case 'name':
          default:
            return d['MODEL'];
        }
      })
      .style('text-anchor', 'middle');
    this.svgContentText = this.svgContent.append('text');
    this.svgContentText
      .attr('x', 0)
      .attr('y', 60)
      .attr('dy', '.35em')
      .text(
        (d) =>
          `${(
            Number.parseFloat(d[this.factor]?.index ?? d[this.factor]) * 100
          ).toFixed(2)} %`
      )
      .style('text-anchor', 'middle');
    this.arrowUse = this.svgContent
      .append('use')
      .attr('xlink:href', '#arrow')
      .attr('x', -30)
      .attr('y', -30)
      .attr(
        'transform',
        // rotation is defined clockwise, hence -45 deg will turn the arrow up
        (d) =>
          `rotate(${
            -45 *
            this.yearGraphService.getRegionProgress(d, {factor: this.factor})
          }, 0, 0)`
      );
  }

  updateGraph(): void {
    const year = this.yearGraphService.selectedYear.toString().includes('.')
      ? this.yearGraphService.selectedYear
      : this.yearGraphService.selectedYear + '.0';
    this.regionData = this.sdmDihService.sdmData[year].find(
      (row) => row['MODEL'] === this.region && row['SCENARIO'] === this.scenario
    );
    this.svgContent
      .data(() => [this.regionData])
      .select('circle')
      .attr('fill', (d) => {
        return this.sdmDihService.perc2color(
          d[this.factor]?.index ?? d[this.factor]
        );
      });
    this.svgContentText
      .data([this.regionData])
      .text(
        (d) =>
          `${(
            Number.parseFloat(d[this.factor]?.index ?? d[this.factor]) * 100
          ).toFixed(2)} %`
      );
    this.arrowUse.data([this.regionData]).attr(
      'transform',
      // rotation is defined clockwise, hence -45 deg will turn the arrow up
      (d) =>
        `rotate(${
          -45 *
          this.yearGraphService.getRegionProgress(d, {factor: this.factor})
        }, 0, 0)`
    );
  }
}
