from dataclasses import dataclass
from typing import Optional

from django.apps import apps
from django.db import models
from django.urls import reverse
from scrobbles.dataclasses import BaseLogData
from scrobbles.constants import MediaType
from scrobbles.mixins import ScrobblableConstants, ScrobblableItem

BNULL = {"blank": True, "null": True}

TODOIST_TASK_URL = "https://app.todoist.com/app/task/{id}"


@dataclass
class TaskLogData(BaseLogData):
    title: Optional[str] = None
    labels: Optional[list[str]] = None

    orgmode_id: Optional[str] = None
    orgmode_state: Optional[str] = None
    orgmode_properties: Optional[dict] = None
    orgmode_drawers: Optional[list] = None
    orgmode_timestamps: Optional[list] = None

    todoist_id: Optional[str] = None
    todoist_project_id: Optional[str] = None

    _excluded_fields = {
        "labels",
        "orgmode_id",
        "orgmode_state",
        "orgmode_properties",
        "orgmode_drawers",
        "orgmode_timestamps",
        "todoist_id",
        "todoist_project_id",
    }

    def notes_as_str(self) -> str:
        """Return formatted notes with line breaks and no keys"""
        labels_str = ""
        if self.labels:
            labels_str = ", ".join(self.labels)

        lines = []
        if self.notes:
            for note in self.notes:
                if isinstance(note, dict):
                    timestamp, note_text = next(iter(note.items()))
                    # Flatten newlines and clean whitespace
                    note_text = " ".join(note_text.strip().split())
                    lines.append(f"{timestamp}: {note_text} [{labels_str}]")
                if isinstance(note, str):
                    lines.append(note)

        return "\n".join(lines)


class Task(ScrobblableItem):
    """Basically a holder for Todoist Tasks
    and any other otherwise generic tasks.

    """
    MEDIA_TYPE = MediaType.TASK

    scrobblableitem_ptr = models.OneToOneField(
        ScrobblableItem,
        parent_link=True,
        primary_key=True,
        on_delete=models.CASCADE,
        related_name="as_task",
    )

    def __str__(self):
        return self.title

    def get_absolute_url(self):
        return reverse("tasks:task_detail", kwargs={"slug": self.uuid})

    @property
    def strings(self) -> ScrobblableConstants:
        return ScrobblableConstants(verb="Doing", tags="memo")

    @property
    def logdata_cls(self):
        return TaskLogData

    def source_url_for_user(self, user_id) -> str:
        url = ""
        scrobble = self.scrobbles(user_id).first()
        if scrobble:
            if scrobble.log.get("source") == "todoist":
                url = TODOIST_TASK_URL.format(id=scrobble.logdata.todist_id)
        return url

    def subtitle_for_user(self, user_id):
        scrobble = self.scrobbles(user_id).first()
        return scrobble.logdata.title or scrobble.log.get("title")

    @classmethod
    def find_or_create(cls, title: str) -> "Task":
        task, created = cls.objects.get_or_create(title=title)
        if created:
            task.base_run_time_seconds = 1800
            task.save(update_fields=["base_run_time_seconds"])

        return task

    def scrobbles(self, user_id):
        Scrobble = apps.get_model("scrobbles", "Scrobble")
        return Scrobble.objects.filter(user_id=user_id, task=self).order_by(
            "-timestamp"
        )
