// Author: irontiga <irontiga@gmail.com>

import { html, LitElement, css } from 'lit'
import * as WORDLISTS from './wordList'

class RandomSentenceGenerator extends LitElement {
	static get properties() {
		return {
			template: { type: String, attribute: 'template' },
			parsedString: { type: String },
			fetchedWordlistCount: { type: Number, value: 0 },
			capitalize: { type: Boolean },
			partsOfSpeechMap: { type: Object },
			templateEntropy: { type: Number, reflect: true, attribute: 'template-entropy' },
			maxWordLength: { type: Number, attribute: 'max-word-length' }
		}
	}

	constructor() {
		super()
		this.template = 'adjective noun verb adverb.'
		this.maxWordLength = 0
		this.parsedString = ''
		this.fetchedWordlistCount = 0
		this.capitalize = true
		this.partsOfSpeechMap = {
			'noun': 'nouns',
			'adverb': 'adverbs',
			'adv': 'adverbs',
			'verb': 'verbs',
			'interjection': 'interjections',
			'adjective': 'adjectives',
			'adj': 'adjectives',
			'verbed': 'verbed'
		}
		this.partsOfSpeech = Object.keys(this.partsOfSpeechMap)
		this._wordlists = WORDLISTS
	}

	static styles = css`
    div {
      text-align: center;
	  width: 100%;
	  background-color: #1f2023;
	  border-radius: 5px;
	  padding: 10px;
    }
  `;

	render() {
		return html`
			<div>${this.parsedString}</div>
		`
	}

	

	firstUpdated() {
		// ...
	}

	updated(changedProperties) {
		let regen = false

		if (changedProperties.has('template')) {
			regen = true
		}

		if (changedProperties.has('maxWordLength')) {
			console.dir(this.maxWordLength)

			if (this.maxWordLength) {
				const wl = { ...this._wordlists }

				for (const partOfSpeech in this._wordlists) {
					if (Array.isArray(this._wordlists[partOfSpeech])) {
						wl[partOfSpeech] = this._wordlists[partOfSpeech].filter(word => word.length <= this.maxWordLength)
					}
				}

				this._wordlists = wl
			}

			regen = true
		}

		if (regen) this.generate()
	}

	_RNG(entropy) {
		if (entropy > 1074) {
			throw new Error('Javascript can not handle that much entropy!')
		}

		let randNum = 0

		const crypto = window.crypto || window.msCrypto

		if (crypto) {
			const entropy256 = Math.ceil(entropy / 8)

			let buffer = new Uint8Array(entropy256)

			crypto.getRandomValues(buffer)

			randNum = buffer.reduce((num, value) => {
				return num * value
			}, 1) / Math.pow(256, entropy256)
		} else {
			console.warn('Secure RNG not found. Using Math.random')

			randNum = Math.random()
		}

		return randNum
	}

	setRNG(fn) {
		this._RNG = fn
	}

	_captitalize(str) {
		return str.charAt(0).toUpperCase() + str.slice(1)
	}

	getWord(partOfSpeech) {
		const words = this._wordlists[this.partsOfSpeechMap[partOfSpeech]]
		const requiredEntropy = Math.log(words.length) / Math.log(2)
		const index = this._RNG(requiredEntropy) * words.length

		return {
			word: words[Math.round(index)],
			entropy: words.length
		}
	}

	generate() {
		this.parsedString = this.parse(this.template)
	}

	parse(template) {
		const split = template.split(/[\s]/g)

		let entropy = 1

		const final = split.map(word => {
			const lower = word.toLowerCase()

			this.partsOfSpeech.some(partOfSpeech => {
				const partOfSpeechIndex = lower.indexOf(partOfSpeech) // Check it exists
				const nextChar = word.charAt(partOfSpeech.length)

				if (partOfSpeechIndex === 0 && !(nextChar && (nextChar.match(/[a-zA-Z]/g) != null))) {
					const replacement = this.getWord(partOfSpeech)
					word = replacement.word + word.slice(partOfSpeech.length) // Append the rest of the "word" (punctuation)
					entropy = entropy * replacement.entropy

					return true
				}
			})

			return word
		})

		this.templateEntropy = Math.floor(Math.log(entropy) / Math.log(8))

		return final.join(' ')
	}
}

window.customElements.define('random-sentence-generator', RandomSentenceGenerator)

export default RandomSentenceGenerator