from typing import Dict, Optional
import webbrowser
from talon import ctrl, ui, Module, Context, actions, clip, app
from dataclasses import dataclass
from things3.things3 import Things3
from ...code.create_spoken_forms import create_spoken_forms
import io
import csv

ctx = Context()
mod = Module()
apps = mod.apps
apps.things3 = """
app.name: Things
"""
ctx.matches = r"""
app: things3
"""

mod.list("things_tag", desc="Tags in Things")
mod.list("things_tag_with_shortcut", desc="Tags in Things within an assigned shortcut")
mod.list("things_project", desc="Areas and projects in Things")

things = Things3()


@dataclass
class Tag:
    uuid: str
    title: str
    shortcut: Optional[str]


@dataclass
class Project:
    uuid: str
    title: str


raw_areas = things.get_areas()
raw_projects = things.get_projects()
sql_query = f"""
SELECT TAG.title, TAG.shortcut, TAG.uuid
FROM {things.TABLE_TAG} AS TAG
"""
tags = [Tag(**raw_tag) for raw_tag in things.execute_query(sql_query)]
projects = [
    Project(uuid=raw_project["uuid"], title=raw_project["title"])
    for raw_project in raw_areas + raw_projects
]

tag_map: Dict[str, Tag] = {tag.uuid: tag for tag in tags}
project_map = {project.uuid: project for project in projects}

ctx.lists["self.things_tag"] = {
    spoken_form: tag.uuid
    for tag in tags
    for spoken_form in create_spoken_forms(tag.title)
}
ctx.lists["self.things_tag_with_shortcut"] = {
    spoken_form: tag.uuid
    for tag in tags
    if tag.shortcut is not None
    for spoken_form in create_spoken_forms(tag.title)
}
things_projects = {
    spoken_form: project.uuid
    for project in projects
    for spoken_form in create_spoken_forms(project.title)
}
print(things_projects)
ctx.lists["self.things_project"] = things_projects


@mod.action_class
class Actions:
    def tag_todo(things_tags: str):
        """Tag todo with a list of tags"""
        tag_list = [tag_map[tag_uuid] for tag_uuid in things_tags.split(",")]
        tags_with_shortcuts = [tag for tag in tag_list if tag.shortcut is not None]
        tags_without_shortcuts = [tag for tag in tag_list if tag.shortcut is None]

        for tag in tags_with_shortcuts:
            actions.key(f"ctrl-{tag.shortcut}")

        for tag in tags_without_shortcuts:
            actions.key(f"cmd-shift-t")
            actions.insert(tag.title)
            actions.key("enter")

    def filter_by_tag(things_tags: str):
        """Tag todo with a list of tags"""
        tag_list = [tag_map[tag_uuid] for tag_uuid in things_tags.split(",")]

        for tag in tag_list:
            if tag.shortcut is None:
                raise Exception("Can only filter by tags with assigned shortcuts")
            actions.key(f"ctrl-alt-{tag.shortcut}")

    def show_tag(things_tag: str):
        """Show a particular tag in things"""
        tag = tag_map[things_tag]
        webbrowser.open(f"things:///show?id={tag.uuid}")

    def show_things_list(things_project: str):
        """Show a list in things"""
        project = project_map[things_project]
        webbrowser.open(f"things:///show?id={project.uuid}")

    def move_todo(project: str):
        """Move todo to a particular list"""
        try:
            project = project_map[project].title
        except KeyError:
            pass
        actions.key("cmd-shift-m")
        actions.insert(project)
        actions.key("enter")


@mod.capture(rule="{self.things_tag}+")
def things_tags(m) -> str:
    "One or more Things tags"
    return ",".join(m.things_tag_list)


@mod.capture(rule="{self.things_tag_with_shortcut}+")
def things_tags_with_shortcut(m) -> str:
    "One or more Things tags"
    return ",".join(m.things_tag_with_shortcut_list)


@mod.capture(rule="{self.things_project}+")
def things_projects(m) -> str:
    "One or more Things projects"
    return to_csv_row_string(m.things_project_list)


def to_csv_row_string(row_elements: str) -> str:
    output = io.StringIO()
    writer = csv.writer(output, quoting=csv.QUOTE_MINIMAL)
    writer.writerow(row_elements)
    return output.getvalue()
