<script lang="ts">
  import { onMount } from 'svelte';
  import initWasm from '@vlcn.io/crsqlite-wasm';
	import wasmUrl from '@vlcn.io/crsqlite-wasm/crsqlite.wasm?url';
  import { start } from "@vlcn.io/ws-client/worker.js";
  import { createDbProvider } from "@vlcn.io/ws-browserdb";
  import * as addParser from '../../parser/add_parser.js';

  let db;
	let ws;
  let todos = [];
  let newTodo = '';

  onMount(async () => {
    const sqlite = await initWasm(() => wasmUrl);
    db = await sqlite.open('todo.db');

    await db.exec(`
			CREATE TABLE IF NOT EXISTS todos (
			id BLOB PRIMARY KEY NOT NULL,
			description TEXT,
      project text,
      tags text,
      due text,
      wait text,
      priority text,
      urgency real,
			completed INTEGER NOT NULL DEFAULT 0
		);
		SELECT crsql_as_crr('todos');
    `);

		const config = {
      dbProvider: createDbProvider(),
		  transportProvider: (dbName) => new WebSocket(`ws://localhost:8080/sync/${dbName}`),
    };

    start(config);

		ws = new WebSocket('ws://localhost:8080/sync');

		db.onUpdate(async () => {
			const changes = await db.execA(`SELECT * FROM crsql_changes WHERE db_version > 0 AND site_id = crsql_site_id()`);

			sendChangesToServer(changes);
    });

		ws.onmessage = async function(event) {
        const { type, data } = JSON.parse(event.data);
        if (type === 'changes') {
            await applyChanges(data);
        }
    };

    loadTodos();
  });

	function sendChangesToServer(changes) {
    const formattedChanges = changes.map(change => ({
        TableName: change[0],
        PK: Array.isArray(change[1]) ? btoa(String.fromCharCode.apply(null, change[1])) : btoa(change[1]),
        ColumnName: change[2],
        Value: Array.isArray(change[3]) ? btoa(String.fromCharCode.apply(null, change[3])) : change[3],
        ColVersion: Number(change[4]),
        DBVersion: Number(change[5]),
        SiteID: Array.isArray(change[6]) ? btoa(new TextDecoder('utf8').decode(change[6])) : btoa(change[6]),
        CL: Number(change[7]),
        Seq: Number(change[8])
    }));
		console.log(formattedChanges)

    const message = {
        type: "changes",
        data: formattedChanges
    };

    ws.send(JSON.stringify(message));
}


  async function applyChanges(changes) {
    await db.tx(async (tx) => {
        for (const change of changes) {
            await tx.exec(
                `INSERT INTO crsql_changes VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
                change
            );
        }
    });
	}

  async function loadTodos() {
    const result = await db.execO("SELECT * FROM todos ORDER BY id");
    todos = result;
  }

  // TODO:
  // This is fucking sucks
  // make the stupid parser do this 😩
  async function Marshall(parsed) {
    let project = "";
    const tags = [];
    console.log(parsed);
    for (const attr of parsed.attributes) {
      console.log(attr);
      switch (attr.type) {
        case 'project':
          console.log("project" + attr.value);
          project = attr.value;
          break;
        case 'tag':
          console.log("tag" + attr.value);
          tags.push(attr.value);
          break;
      }
    }
    return {description: parsed.description, tags: tags, project: project};
  }

  async function addTodo() {
    if (newTodo.trim()) {
      const parsed = await Marshall(addParser.parse(newTodo));
      console.log(parsed);
      await db.exec(`
        INSERT INTO todos (id, description, tags, project, completed)
        VALUES (lower(hex(randomblob(16))), ?, ?, ?, 0)
      `, [parsed.description, JSON.stringify(parsed.tags), parsed.project]);
      newTodo = '';
      loadTodos();
    }
  }

  async function toggleTodo(id) {
    await db.exec(`
      UPDATE todos
      SET completed = NOT completed
      WHERE id = ?
    `, [id]);
    loadTodos();
  }
</script>

<main>
  <h1>Mast</h1>
  <input
    bind:value={newTodo}
    on:keypress={(e) => e.key === 'Enter' && addTodo()}
    placeholder="Add a new todo"
  />
  <button on:click={addTodo}>Add Todo</button>
  <ul>
    {#each todos as todo}
      <li>
        <input
          type="checkbox"
          checked={todo.completed}
          on:change={() => toggleTodo(todo.id)}
        />
        <span class:completed={todo.completed}>{todo.description} pro:{todo.project} {todo.tags}</span>
      </li>
    {/each}
  </ul>
</main>

<style>
  .completed {
    text-decoration: line-through;
  }
</style>

