import { Diagram } from './Diagram'
import { readFileSync } from 'fs'
import { join } from 'path'

type StringType = 'open' | 'muted' | 'played'

export interface SvgDiagramOptions {
  fretWidth?: number
  fretHeight?: number
  stringLineColor?: string
  stringLineWidth?: number
  fretLineColor?: string
  fretLineWidth?: number
  fingerOrBarreWidth?: number
  fingerOrBarreLineWidth?: number
  fingerOrBarreLineColor?: string
  openStringSymbolColor?: string
  openStringSymbolLineColor?: string
}

export class SvgDiagram {
  static svgDefs: string = readFileSync(join(__dirname, 'chord-defs.svg'), { encoding: 'utf8' })
  diagram: Diagram

  constructor (diagram: Diagram, options?: SvgDiagramOptions) {
    this.diagram = diagram
  }

  get openStrings (): number[] {
    return this.diagram.fretStrings['0'] ?? []
  }

  get mutedStrings (): number[] {
    return this.diagram.fretStrings['-1'] ?? []
  }

  get playedStrings (): number[] {
    const playedStrings: number[] = []
    this.diagram.stringFrets.forEach((fret, string) => {
      if (fret > 0) { playedStrings.push(string) }
    })
    return playedStrings
  }

  svg (showVariant?: boolean): string {
    let minFret: number = this.diagram.minFret
    // make sure there are at most five frets
    if (this.diagram.maxFret - minFret > 4) minFret = this.diagram.maxFret - 4
    // don't capo if a chord is within the first five frets
    if (this.diagram.maxFret <= 5) minFret = 1

    return `
<svg width="64" height="64">
  ${this.svgTitle(showVariant)}
  <g class="chord-chord" transform="translate(8.5,13.5)">
    <use href="#chord-diapason" x="0" y="0" />
    ${this.svgNut(minFret)}
    ${this.svgMinFretText(minFret)}
    ${this.svgFingersOrBarres(minFret)}
    ${this.svgStrings('muted')}
    ${this.svgStrings('open')}
    ${this.svgStrings('played')}
  </g>
</svg>`
  }

  private svgTitle (showVariant?: boolean): string {
    let title = ''
    if (this.diagram.chordName !== undefined) {
      title = this.diagram.chordName
      if (showVariant === true && this.diagram.chordVariant !== undefined) {
        title = `${title}:${this.diagram.chordVariant}`
      }
    }
    return (title !== '') ? `<text class="chord-name" x="26" y="0" dominant-baseline="hanging" text-anchor="middle">${title}</text>` : ''
  }

  private svgNut (minFret: number): string {
    return (minFret > 1) ? '' : '<use href="#chord-nut" x="0" y="0" />'
  }

  private svgMinFretText (minFret: number): string {
    return (minFret > 1)
      ? `<text class="chord-min-fret" x="38" y="6.5" dominant-baseline="middle">${String(minFret)}</text>`
      : ''
  }

  private svgFingersOrBarres (minFret: number): string {
    let ret = ''
    this.diagram.fingersAndBarrels.forEach(barre => {
      const barreLength = barre.stringTo - barre.stringFrom + 1
      ret += `<use href="#chord-barre${barreLength}" x="${barre.stringFrom * 7}" y="${(barre.fret - minFret) * 8}" />`
    })
    return `<g class="chord-fingers-and-barres" transform="translate(-2,4)">${ret}</g>`
  }

  private svgStrings (stringType: StringType): string {
    let ret = ''
    const shape = (stringType === 'played') ? 'barre1' : stringType

    this[`${(stringType)}Strings`].forEach((chordString: number) => {
      ret += `<use href="#chord-${shape}" x="${chordString * 7}" y="0" />`
    })
    return `<g class="chord-${stringType}-strings" transform="translate(-2,46)">${ret}</g>`
  }
}
