# -*- coding: utf-8 -*-

# Copyright (c) 2005 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing a class to store task data.
"""

import contextlib
import enum
import os
import time

from PyQt6.QtCore import Qt, QUuid
from PyQt6.QtWidgets import QTreeWidgetItem

import UI.PixmapCache
import Preferences


class TaskType(enum.IntEnum):
    """
    Class defining the task types.
    """
    NONE = 255
    FIXME = 0
    TODO = 1
    WARNING = 2
    NOTE = 3
    TEST = 4
    DOCU = 5


class TaskPriority(enum.IntEnum):
    """
    Class defining the task priorities.
    """
    HIGH = 0
    NORMAL = 1
    LOW = 2


class Task(QTreeWidgetItem):
    """
    Class implementing the task data structure.
    """
    TaskType2IconName = {
        TaskType.FIXME: "taskFixme",                # __NO-TASK__
        TaskType.TODO: "taskTodo",                  # __NO-TASK__
        TaskType.WARNING: "taskWarning",            # __NO-TASK__
        TaskType.NOTE: "taskNote",                  # __NO-TASK__
        TaskType.TEST: "taskTest",                  # __NO-TASK__
        TaskType.DOCU: "taskDocu",                  # __NO-TASK__
    }
    TaskType2ColorName = {
        TaskType.FIXME: "TasksFixmeColor",          # __NO-TASK__
        TaskType.TODO: "TasksTodoColor",            # __NO-TASK__
        TaskType.WARNING: "TasksWarningColor",      # __NO-TASK__
        TaskType.NOTE: "TasksNoteColor",            # __NO-TASK__
        TaskType.TEST: "TasksTestColor",            # __NO-TASK__
        TaskType.DOCU: "TasksDocuColor",            # __NO-TASK__
    }
    TaskType2MarkersName = {
        TaskType.FIXME: "TasksFixmeMarkers",        # __NO-TASK__
        TaskType.TODO: "TasksTodoMarkers",          # __NO-TASK__
        TaskType.WARNING: "TasksWarningMarkers",    # __NO-TASK__
        TaskType.NOTE: "TasksNoteMarkers",          # __NO-TASK__
        TaskType.TEST: "TasksTestMarkers",          # __NO-TASK__
        TaskType.DOCU: "TasksDocuMarkers",          # __NO-TASK__
    }
    
    def __init__(self, summary, priority=TaskPriority.NORMAL, filename="",
                 lineno=0, completed=False, _time=0, isProjectTask=False,
                 taskType=TaskType.TODO, project=None, description="",
                 uid="", parentUid=""):
        """
        Constructor
        
        @param summary summary text of the task
        @type str
        @param priority priority of the task
        @type TaskPriority
        @param filename filename containing the task
        @type str
        @param lineno line number containing the task
        @type int
        @param completed flag indicating completion status
        @type bool
        @param _time creation time of the task (if 0 use current time)
        @type float
        @param isProjectTask flag indicating a task related to the current
            project
        @type bool
        @param taskType type of the task
        @type TaskType
        @param project reference to the project object
        @type Project
        @param description explanatory text of the task
        @type str
        @param uid unique id of the task
        @type str
        @param parentUid unique id of the parent task
        @type str
        """
        super().__init__()
        
        self.summary = summary
        self.description = description
        self.filename = filename
        self.lineno = lineno
        self.completed = completed
        self.created = _time and _time or time.time()
        self._isProjectTask = isProjectTask
        self.project = project
        if uid:
            self.uid = uid
        else:
            self.uid = QUuid.createUuid().toString()
        self.parentUid = parentUid
        
        if isProjectTask:
            self.filename = self.project.getRelativePath(self.filename)
            
        self.setData(0, Qt.ItemDataRole.DisplayRole, "")
        self.setData(1, Qt.ItemDataRole.DisplayRole, "")
        self.setData(2, Qt.ItemDataRole.DisplayRole, self.summary)
        self.setData(3, Qt.ItemDataRole.DisplayRole, self.filename)
        self.setData(4, Qt.ItemDataRole.DisplayRole, self.lineno or "")
        
        if self.completed:
            self.setIcon(0, UI.PixmapCache.getIcon("taskCompleted"))
            strikeOut = True
        else:
            self.setIcon(0, UI.PixmapCache.getIcon("empty"))
            strikeOut = False
        for column in range(2, 5):
            f = self.font(column)
            f.setStrikeOut(strikeOut)
            self.setFont(column, f)
        
        self.setPriority(priority)
        
        self.setTaskType(taskType)
        self.setTextAlignment(4, Qt.AlignmentFlag.AlignRight)
    
    def colorizeTask(self):
        """
        Public slot to set the colors of the task item.
        """
        boldFont = self.font(0)
        boldFont.setBold(True)
        nonBoldFont = self.font(0)
        nonBoldFont.setBold(False)
        for col in range(5):
            with contextlib.suppress(KeyError):
                self.setBackground(
                    col, Preferences.getTasks(
                        Task.TaskType2ColorName[self.taskType]))
            
            if self._isProjectTask:
                self.setFont(col, boldFont)
            else:
                self.setFont(col, nonBoldFont)
    
    def setSummary(self, summary):
        """
        Public slot to update the description.
        
        @param summary summary text of the task (string)
        """
        self.summary = summary
        self.setText(2, self.summary)
    
    def setDescription(self, description):
        """
        Public slot to update the description field.
        
        @param description descriptive text of the task
        @type str
        """
        self.description = description
    
    def setPriority(self, priority):
        """
        Public slot to update the priority.
        
        @param priority priority of the task
        @type TaskPriority
        """
        self.priority = priority
        
        if self.priority == TaskPriority.NORMAL:
            self.setIcon(1, UI.PixmapCache.getIcon("empty"))
        elif self.priority == TaskPriority.HIGH:
            self.setIcon(1, UI.PixmapCache.getIcon("taskPrioHigh"))
        elif self.priority == TaskPriority.LOW:
            self.setIcon(1, UI.PixmapCache.getIcon("taskPrioLow"))
        else:
            self.setIcon(1, UI.PixmapCache.getIcon("empty"))
    
    def setTaskType(self, taskType):
        """
        Public method to update the task type.
        
        @param taskType type of the task
        @type TaskType
        """
        self.taskType = taskType
        
        try:
            self.setIcon(2, UI.PixmapCache.getIcon(
                Task.TaskType2IconName[self.taskType]))
        except KeyError:
            self.setIcon(2, UI.PixmapCache.getIcon("empty"))
        
        self.colorizeTask()
    
    def setCompleted(self, completed):
        """
        Public slot to update the completed flag.
        
        @param completed flag indicating completion status (boolean)
        """
        self.completed = completed
        if self.completed:
            self.setIcon(0, UI.PixmapCache.getIcon("taskCompleted"))
            strikeOut = True
        else:
            self.setIcon(0, UI.PixmapCache.getIcon("empty"))
            strikeOut = False
        for column in range(2, 5):
            f = self.font(column)
            f.setStrikeOut(strikeOut)
            self.setFont(column, f)
        
        # set the completion status for all children
        for index in range(self.childCount()):
            self.child(index).setCompleted(completed)
    
    def isCompleted(self):
        """
        Public slot to return the completion status.
        
        @return flag indicating the completion status (boolean)
        """
        return self.completed
    
    def getFilename(self):
        """
        Public method to retrieve the task's filename.
        
        @return filename (string)
        """
        if self._isProjectTask and self.filename:
            return os.path.join(self.project.getProjectPath(), self.filename)
        else:
            return self.filename
    
    def isFileTask(self):
        """
        Public slot to get an indication, if this task is related to a file.
        
        @return flag indicating a file task (boolean)
        """
        return self.filename != ""
    
    def getLineno(self):
        """
        Public method to retrieve the task's linenumber.
        
        @return linenumber (integer)
        """
        return self.lineno
    
    def getUuid(self):
        """
        Public method to get the task's uid.
        
        @return uid (string)
        """
        return self.uid
    
    def getParentUuid(self):
        """
        Public method to get the parent task's uid.
        
        @return parent uid (string)
        """
        return self.parentUid
    
    def setProjectTask(self, pt):
        """
        Public method to set the project relation flag.
        
        @param pt flag indicating a project task (boolean)
        """
        self._isProjectTask = pt
        self.colorizeTask()
    
    def isProjectTask(self):
        """
        Public slot to return the project relation status.
        
        @return flag indicating the project relation status (boolean)
        """
        return self._isProjectTask
    
    def isProjectFileTask(self):
        """
        Public slot to get an indication, if this task is related to a
        project file.
        
        @return flag indicating a project file task (boolean)
        """
        return self._isProjectTask and self.filename != ""
    
    def toDict(self):
        """
        Public method to convert the task data to a dictionary.
        
        @return dictionary containing the task data
        @rtype dict
        """
        return {
            "summary": self.summary.strip(),
            "description": self.description.strip(),
            "priority": self.priority.value,
            "lineno": self.lineno,
            "completed": self.completed,
            "created": self.created,
            "type": self.taskType.value,
            "uid": self.uid,
            "parent_uid": self.parentUid,
            "expanded": self.isExpanded(),
            "filename": self.getFilename(),
        }
