<script>
	import Importabular from "importabular"
	import showdown from "showdown"

	let converter = new showdown.Converter({
		simplifiedAutoLink: true, // automatically convert links...
		excludeTrailingPunctuationFromURLs: true, // ...but not the trailing punctuation
		openLinksInNewWindow: true, // don't forget to open in new window!
		simpleLineBreaks: true, // use two line breaks to start a new paragraph
		emoji: true, // because why not 😉
		strikethrough: true, // ~~that also~~
	})

	let editor

	let emailContent = 'Hi [TK name],\n\nIt\'s been a while since we heard from you. How are you doing? Your last article [TK article] did quite well, and we were wondering if you\'d be interested in writing a sequel?\n\nCheers,  \nThe Snipette Team[TK PS]'

	let sheetOne
	let step = 0
	let tkList = []

	let fromEmail = ''
	let subject = ''

	let cookiePreviewData = { text: '', email: ''}
	let cookiePreviewRow = 0

	function showEmail() {
		step = 1
	}

	function detectFields(value) {
		if (!value) return []

		let matches = value.match(/\[TK (\w+?)\]/gm)
		let tkList = []

		if (!!matches) {
			let propertyRegex = new RegExp(/\[TK (\w+)\]/)
			for (let m of matches) {
				tkList.push(propertyRegex.exec(m)[1])
			}
		}

		// remove duplicates
		tkList = [...new Set(tkList)]

		return tkList
	}

	$: tkList = detectFields(emailContent)

	function showSheet() {
		// Figure out columns
		let columns = []

		if (!tkList.includes('email')) {
			columns.push({
				label: 'email',
				description: 'Email address of the recipient',
				placeholder: 'someone@members.snipettemag.com',
			})
		}

		for (let tk of tkList) {
			columns.push({
				label: tk,
			})
		}

		// First sheet
		sheetOne = new Importabular({
			node: editor,
			columns: columns,
			onChange(data) {
				cookiePreviewData = getPreview()
			}
		})

		step = 2

		// for debugging only
		window.sheetOne = sheetOne
	}

	/**
	 * Refresh sheet
	 *
	 * Destroys the current sheet, but saves the data first so if
	 * there are any columns in the new sheet that matches the old
	 * ones, it'll add them back. (Columns meaning TKs, of course)
	 */

	function refreshSheet() {
		let oldData = sheetOne.getData()
		let oldColumns = sheetOne.columns.map(c => c.label)

		sheetOne.destroy()

		// now, make it up again with the new TKs
		showSheet()

		// figure out the new data
		let newData = []
		let tkOrder = []

		// first, we figure out how the old column order corresponds to
		// the new one

		for (let col of sheetOne.columns.map(c => c.label)) {
			tkOrder.push(oldColumns.indexOf(col))
		}

		// now we fill this, row by row
		for (let oldRow of oldData) {

			// skip empty rows
			if (oldRow.every(v => !v)) continue

			// now, we figure out what to put for the new row
			let newRow = []
			for (let tkIndex of tkOrder) {
				if (tkIndex <= -1) {
					// new TK; leave it blank
					newRow.push('')
				} else {
					// old TK; keep it filled!
					newRow.push(oldRow[tkIndex])
				}
			}

			// and finally, when all is done, we save it.
			newData.push(newRow)
		}

		// fill it with the new data
		sheetOne.setData(newData)

		// don't forget to refresh the preview!
		cookiePreviewData = getPreview()
	}

	function incrementPreviewRow() {
		let sheetLength = sheetOne.getData().length

		// make sure it's not too big...
		if (cookiePreviewRow >= sheetLength-1) {
			cookiePreviewRow = sheetLength - 1
		} else if (cookiePreviewRow < 0) {
			// ...and not too small
			cookiePreviewRow = 0
		} else {
			// if not, then make it "just right"! :)
			cookiePreviewRow++
		}
	}

	function decrementPreviewRow() {
		let sheetLength = sheetOne.getData().length
		// make sure it's not too small...
		if (cookiePreviewRow >= sheetLength) {
			// ...and not too big
			cookiePreviewRow = sheetLength - 1
		} else if (cookiePreviewRow <= 0) {
			// if not, then make it "just right"! :)
			cookiePreviewRow = 0
		} else {
			cookiePreviewRow--
		}
	}

	function getPreview(row) {
		if (!row) row = cookiePreviewRow
		let previewText = emailContent

		// get the row we're working on
		if (!sheetOne) return '' // no sheet to get data from :(
		let data = sheetOne.getData()
		if (row < 0 || data.length < row) return previewText // no row to apply :(
		let r = data[row]

		for (let tk of tkList) {
			// figure out which column holds values for this TK
			let tkIndex = sheetOne.columns.findIndex(t => t.label == tk)

			// replace it!
			previewText = previewText.replace(new RegExp(`\\[TK ${tk}\\]`, 'g'), r[tkIndex])
		}

		// save the email
		let previewEmail = r[sheetOne.columns.findIndex(t => t.label == 'email')]

		return { text: previewText, email: previewEmail }
	}

	// automatically update
	$: cookiePreviewData = getPreview(cookiePreviewRow)

	function next() {
		step += 1
	}

	function prev() {
		step -= 1
	}

	function stepOne() {
		step = 1
	}

	function stepTwo() {
		step = 2
	}

	// This is to display which email is sending next
	let nowSending

	// And this is for the progress bar, mainly
	let emailsSoFar = 0
	let emailsToSend = 0

	/**
	 * Hit Send
	 *
	 * collates all the data for sending, and passes it
	 * on to the backend for actual processing. Note that here we
	 * cookie-cut the emails on the frontend itself; the backend
	 * just blindly takes what it gets. We're doing this so that we
	 * can use the same getPreview() function and be consistent: we
	 * don't want the final to suddenly end up looking very different
	 * from the preview!
	 */
	function hitSend() {
		step = 4
		let emails = []

		// process the 'i'th row of the sheet, one by one
		for (let i=0; i<sheetOne.getData().length; i++) {
			let previewData = getPreview(i)

			// skip if email is blank
			if (!previewData.email) continue

			// add it to the list of emails to be sent
			emails.push({
				from: fromEmail,
				to: previewData.email,
				subject: subject,
				text: previewData.text,
				html: converter.makeHtml(previewData.text),
			})
		}

		// keep track of how many we had to start witth
		emailsToSend = emails.length
		emailsSoFar = 0

		// okay, now let's open a socket to the server!
		let socketProtocol = (window.location.protocol === 'https:' ? 'wss:' : 'ws:')
		let socketUrl = socketProtocol + '//' + window.location.host + window.location.pathname + 'hit-send/'
		let socket = new WebSocket(socketUrl)

		socket.onopen = function() {
			nowSending = emails.shift()
			socket.send(JSON.stringify(nowSending))
		}

		socket.onmessage = (message) => {
			try {
				message = JSON.parse(message.data)
			} catch (err) {
				console.error(`Received malformed response from server: ${message.data}`)
				return
			}

			if (message.success) {
				console.log(`${message.to}'s email sent successfully!`)

				// send the next one
				nowSending = emails.shift()
				if (!!nowSending) {
					socket.send(JSON.stringify(nowSending))
					console.log(`Sending: ${nowSending.to}`)

					// update the counter for the progress bar
					emailsSoFar += 1
				} else {
					socket.close()
					step = 5
				}
			} else {
				console.error('Something went wrong :(')
				step = 3
			}
		}
	}
</script>

<main>
	{#if step < 4}
		<img src="assets/email-baker.png" class="main-pic" alt="Email Oven"/>
		<h1>Chip <span class="highlight">Choc</span></h1>
		<h2>Cookie-cutter emails made easy.</h2>

		{#if step >= 1}
		<h3 class="mt-3">Step 1</h3>
		{/if}

		{#if step == 0}
			<button on:click={showEmail}>Start Drafting</button>
		{/if}

		{#if step >= 1}
		<div class="instructions">
			<p>Compose your email below, leaving [TK stuff] to be replaced in the table. Make sure each TK is a single word: no spaces allowed!</p>
		</div>

		<div class="email-content">
			<div class="header">
				<div class="form-group">
					From
					<input type="text" placeholder="chipchoc@example.com" bind:value={fromEmail}/>
				</div>
				<div class="form-group">
					Subject
					<input type="text" placeholder="Hi there" bind:value={subject}/>
				</div>
			</div>
			<textarea bind:value={emailContent}/>
			<p>
				<strong>Detected fields:</strong>
				{#each tkList as tk (tk)}
					<span class="tag">{tk}</span>
				{/each}
			</p>
		</div>
		{/if}

		{#if step >= 2}
		<h3 class="mt-3">Step 2</h3>
		<div class="instructions">
			<p>Now, fill in the fields for each user. (You can also copy-paste rows and columns directly from Air, if the ordering is right!)</p>
		</div>
		{/if}

		{#if step == 1}
		<button on:click={showSheet}>Next</button>
		{/if}

		{#if step > 1}
		<button on:click={refreshSheet}>Refresh</button>
		{/if}

		<div id="editor" bind:this={editor}></div>

		{#if step >= 2 && !!cookiePreviewData}
		<h4 class="mt-3">Preview</h4>

		<div class="cookie-preview">
			<div class="preview-header">
				<p>From: {fromEmail || '[NOBODY!!!]'}</p>
				<p>To: {cookiePreviewData.email || '[NOBODY!!!]'}</p>
				<p>Subject: {subject || '[NO SUBJECT #notgood]'}</p>
				<hr />
			</div>
			{@html converter.makeHtml(cookiePreviewData.text)}
		</div>
		<button on:click={decrementPreviewRow}>&lt; Prev</button>
		<button on:click={incrementPreviewRow}>Next &gt;</button>

		<h3>Step 3</h3>

			{#if step == 2}
			<div class="instructions">
				<p>If everything looks okay, then we're done! Click on the button below to put the cutter in action.</p>
			</div>
			<button on:click={next}>Yup, send 'em out!</button>
			{/if}

			{#if step == 3}
			<div class="instructions">
				<p>Are you <strong>sure</strong> you want to send them out?</p>
				<p>Are you ready?</p>
				<p>Did you look through all the previews?</p>
				<p>Have you double-checked the names and email IDs to make sure they match?</p>
			</div>
			<button on:click={hitSend}>Hit send!</button> <button on:click={prev}>Ummmm..</button>
			{/if}

		{/if}
	{/if}

	{#if step == 4}
	<img src="assets/email-baking.png" class="main-pic" alt="Email Oven with cookies inside"/>
	<h1><span class={emailsSoFar % 2 == 0 ? 'highlight' : ''}>Chip</span> <span class={emailsSoFar % 2 == 0 ? '' : 'highlight'}>Choc</span></h1>
	<h2>Your cookies are being cut...</h2>
	<progress value={emailsSoFar} max={emailsToSend}>{emailsToSend ? emailsSoFar/emailsToSend*100 : 0} %</progress>

	{#if !!nowSending }
	<div class="cookie-preview">
		<div class="preview-header">
			<p>From: {nowSending.from || '[NOBODY!!!]'}</p>
			<p>To: {nowSending.to || '[NOBODY!!!]'}</p>
			<p>Subject: {subject || '[NO SUBJECT #notgood]'}</p>
			<hr />
			{@html nowSending.html}
		</div>
	</div>
	{/if}
	{/if}

	{#if step == 5}
	<img src="assets/cookies.png" class="main-pic" alt="A Pile of Cookies"/>
	<h1>Wheee<span class="highlight">!</span></h1>
	<h2>All emails sent successfully.</h2>
	<button on:click={stepTwo}>Back to Draft</button>
	<button on:click={stepOne}>Start Over</button>
	{/if}

</main>

<style>
	main {
		text-align: center;
		padding: 1em;
		max-width: 240px;
		margin: 0 auto;
	}

	h1 {
		margin-bottom: 0;
	}

	h1 + h2 {
		margin-top: 0;
	}

	.main-pic {
		max-width: 100%;
	}

	@media (min-width: 640px) {
		main {
			max-width: none;
		}

		.main-pic {
			max-width: 240px;
		}
	}

	.instructions {
		max-width: 640px;
		margin: 0 auto;
	}

	.email-content {
		margin: 4em auto;
	}

	.email-content .header {
		max-width: 640px;
		text-align: left;
		margin: auto;
	}

	.email-content .form-group {
		display: flex;
		align-items: center;
	}

	.email-content .form-group input {
		margin-left: 1em;
		width: 100%;
		border: 0
	}

	.email-content textarea {
		width: 100%;
		max-width: 640px;
		font-family: inherit;
		min-height: 15em;
	}

	.tag {
		margin: 0.2em;
		padding: 0.5em 1em 0.5em 1em;
		background: #ffe3ff;
		border-radius: 1em;
	}

	.cookie-preview {
		text-align: left;
		max-width: 640px;
		margin: auto;
		padding: 1em;
		border: 1px solid black;
	}

	progress {
		width: 100%;
		max-width: 640px;
		margin: 1em;
		color: #800020;
	}

	progress::-moz-progress-bar,
	progress::-webkit-progress-value {
		background-color: #800020;
	}
</style>
