import Quest from "./quest";

const buttons: Array<[number, number, number, number, string, string]> = [
	[20, 200, 80, 80, '-', 'freqm'],
	[115, 200, 80, 80, '+', 'freqp'],
	[220, 200, 80, 80, '-', 'offsetm'],
	[315, 200, 80, 80, '+', 'offsetp'],
	[420, 200, 80, 80, '-', 'ampm'],
	[515, 200, 80, 80, '+', 'ampp'],
	[20, 400, 580, 80, 'Зафисировать параметры', 'check'],
]

enum STATES {
	CONFIG,
	ERROR,
	DONE
}

const inBound = (...args) => {
	const [x, y, x0, y0, w, h] = args
	return x > x0
		&& x < x0 + w
		&& y > y0
		&& y < y0 + h
}

export default class TuneWaves extends Quest {

	private pos: number = 0

	private head: number = 0

	private freq: number = 0
	private offset: number = 0
	private amp: number = 0

	private timeout: number = 0

	private state: STATES = STATES.CONFIG

	private dest: {
		freq: number,
		offset: number
		amp: number
	} = {
		freq: (Math.random() * 6 + 1) | 0,
		offset: (Math.random() * 6 + 1) | 0,
		amp: (Math.random() * 6 + 1) | 0,
	}

	private ready: boolean = false

	public draw(ctx: CanvasRenderingContext2D) {

		ctx.strokeStyle = 'rgba(255, 0, 0, .3)'
		ctx.lineWidth = 4

		ctx.beginPath()
		ctx.moveTo(50, this.point(0, this.dest.offset, this.dest.freq, this.dest.amp))

		for (let i = 0; i <= 500; i += 10) {
			ctx.lineTo(i + 50, this.point(i, this.dest.offset, this.dest.freq, this.dest.amp))
		}

		const len = 300
		for (let i = this.head - len; i <= this.head; i += 20) {
			if (i < 0 || i > 500) continue

			const opacity = .5 - (this.head - i) / len + .2

			ctx.fillStyle = `rgba(255, 0, 0, ${opacity})`

			ctx.fillRect(
				i + 50 - 3,
				this.point(i, this.offset, this.freq, this.amp) - 3,
				6, 6
			)
		}

		ctx.stroke()




		ctx.strokeStyle = '#555'
		ctx.lineWidth = 1

		ctx.strokeRect(50, 40, 500, 120)
		ctx.beginPath()
		for (let i = 100; i <= 500; i+=50) {
			ctx.moveTo(i, 40)
			ctx.lineTo(i, 160)
		}

		ctx.moveTo(50, 100)
		ctx.lineTo(550, 100)

		ctx.stroke()

		if (this.state === STATES.CONFIG) {
			ctx.fillStyle = '#6ab3b4'
			buttons.forEach(([x, y, w, h, text]) => {
				ctx.fillRect(x, y, w, h)
			})

			ctx.fillStyle = '#fff'
			ctx.textAlign = 'center'
			ctx.font = '24px sans-serif'
			buttons.forEach(([x, y, w, h, text]) => {
				ctx.fillText(text, x + w / 2, y + h * 2 / 3 - 5)
			})

			ctx.fillText('Частота', buttons[0][0] + 90, buttons[0][1] + 120)
			ctx.fillText('' + this.freq, buttons[0][0] + 90, buttons[0][1] + 150)

			ctx.fillText('Смещение', buttons[2][0] + 90, buttons[2][1] + 120)
			ctx.fillText('' + this.offset, buttons[2][0] + 90, buttons[2][1] + 150)

			ctx.fillText('Амплитуда', buttons[4][0] + 90, buttons[4][1] + 120)
			ctx.fillText('' + this.amp, buttons[4][0] + 90, buttons[4][1] + 150)
		}

		if (this.state === STATES.ERROR) {
			ctx.fillText('Неверная настройка', 300, 400)
		}

		if (this.state === STATES.DONE) {
			ctx.fillStyle = '#fff'
			ctx.textAlign = 'center'
			ctx.font = '24px sans-serif'

			ctx.fillText('Связь установлена', 300, 400)
			ctx.fillText('Можно начинать передачу', 300, 450)
		}
	}

	private point(x, offset, freq, amp) {
		const _offset = (offset * 25)
		const _freq = freq / 4 + 1
		const _amp = amp * 5 + 10

		const ang = ((this.pos + _offset + x * _freq) % 360)
		return Math.sin(ang * Math.PI / 180) * _amp + 100
	}

	public update(dt) {
		this.pos = (this.pos + dt / 5) % 360

		this.head = (this.head + dt / 5) | 0
		if (this.head > 800) {
			this.head = 0
		}

		if (this.state !== STATES.CONFIG) {
			this.timeout -= dt

			if (this.timeout <= 0) {
				this.ready = this.state == STATES.DONE
				this.state = STATES.CONFIG
			}
		}
	}

	public click(x, y) {
		const button = buttons.find(bound => inBound(x, y, ...bound))
		if (button) {
			const normalize = val => Math.min(8, Math.max(0, val))
			switch (button[5]) {
				case 'freqp': this.freq = normalize(this.freq + 1); break;
				case 'freqm': this.freq = normalize(this.freq - 1); break;
				case 'ampp': this.amp = normalize(this.amp + 1); break;
				case 'ampm': this.amp = normalize(this.amp - 1); break;
				case 'offsetp': this.offset = normalize(this.offset + 1); break;
				case 'offsetm': this.offset = normalize(this.offset - 1); break;
				case 'check':
					this.state = (this.offset === this.dest.offset
						&& this.amp === this.dest.amp
						&& this.freq === this.dest.freq) ?
							STATES.DONE : STATES.ERROR

					this.timeout = 2000
					break;
			}
		}
	}

	public getCursor(x, y) {
		if (buttons.some(bound => inBound(x, y, ...bound))) {
			return 'pointer'
		}

		return 'default'
	}

	public get result() {
		return this.ready
	}
}
