import re
from common import convert_to_kebab_case
from datetime import datetime
import json
from enum import Enum

from metadata import load_metadata

class IconConvertion:
    def __init__(self, name: str, source: str):
        self.name = name
        self.source = source

class Icon:
    def __init__(self, name: str, type: str, categories: list, aliases: list):
        self.name = name
        self.type = type
        self.categories = categories
        self.aliases = aliases

    def to_metadata(self, author: dict) -> dict:
        return {
            "base": self.type,
            "aliases": self.aliases,
            "categories": self.categories,
            "update": {
                "timestamp": datetime.now().isoformat(),
                "author": author
            }
        }
    
    def convertions(self) -> list[IconConvertion]:
        raise NotImplementedError("Method 'files' must be implemented in subclass")
    

class NormalIcon(Icon):
    def __init__(self, icon: str, name: str, type: str, categories: list, aliases: list):
        super().__init__(name, type, categories, aliases)
        self.icon = icon

    def convertions(self) -> list[IconConvertion]:
        return [
            IconConvertion(self.name, self.icon)
        ]
    
    def from_addition_issue_form(input: dict):
        return NormalIcon(
            mapUrlFromMarkdownImage(input, "Paste icon"),
            convert_to_kebab_case(mapFromRequired(input, "Icon name")),
            mapFileTypeFrom(input, "Icon type"),
            mapListFrom(input, "Categories"),
            mapListFrom(input, "Aliases")
        )
    
    def from_update_issue_form(input: dict):
        try:
            name = convert_to_kebab_case(mapFromRequired(input, "Icon name"))
            metadata = load_metadata(name)

            
            return NormalIcon(
                mapUrlFromMarkdownImage(input, "Paste icon"),
                mapFromRequired(input, "Icon name"),
                mapFileTypeFrom(input, "Icon type"),
                metadata["categories"],
                metadata["aliases"]
            )
        except Exception as exeption:
            raise ValueError(f"Icon '{name}' does not exist", exeption)
        
    def from_metadata_update_issue_form(input: dict):
        name = convert_to_kebab_case(mapFromRequired(input, "Icon name"))
        metadata = load_metadata(name)
        
        return NormalIcon(
            None,
            name,
            metadata["base"],
            mapListFrom(input, "Categories"),
            mapListFrom(input, "Aliases")
        )

    

class MonochromeIcon(Icon):
    def __init__(self, lightIcon: str, darkIcon: str, name: str, type: str, categories: list, aliases: list):
        super().__init__(name, type, categories, aliases)
        self.lightIcon = lightIcon
        self.darkIcon = darkIcon
    
    def to_colors(self) -> dict:
        try:
            metadata = load_metadata(self.name)
            return {
                "light": f"{metadata['colors']['light']}",
                "dark": f"{metadata['colors']['dark']}"
            }
        except:
            return {
                "light": f"{self.name}",
                "dark": f"{self.name}-dark"
            }

    def to_metadata(self, author: dict) -> dict:
        metadata = super().to_metadata(author)
        metadata["colors"] = self.to_colors()
        return metadata
    
    def convertions(self) -> list[IconConvertion]:
        colorNames = self.to_colors()
        return [
            IconConvertion(colorNames["light"], self.lightIcon),
            IconConvertion(colorNames["dark"], self.darkIcon),
        ]
    
    def from_addition_issue_form(input: dict):
        return MonochromeIcon(
            mapUrlFromMarkdownImage(input, "Paste light mode icon"),
            mapUrlFromMarkdownImage(input, "Paste dark mode icon"),
            convert_to_kebab_case(mapFromRequired(input, "Icon name")),
            mapFileTypeFrom(input, "Icon type"),
            mapListFrom(input, "Categories"),
            mapListFrom(input, "Aliases")
        )
    
    def from_update_issue_form(input: dict):
        try:
            name = convert_to_kebab_case(mapFromRequired(input, "Icon name"))
            metadata = load_metadata(name)
            
            return MonochromeIcon(
                mapUrlFromMarkdownImage(input, "Paste light mode icon"),
                mapUrlFromMarkdownImage(input, "Paste dark mode icon"),
                mapFromRequired(input, "Icon name"),
                mapFileTypeFrom(input, "Icon type"),
                metadata["categories"],
                metadata["aliases"]
            )
        except Exception as exeption:
            raise ValueError(f"Icon '{name}' does not exist", exeption)
        
    def from_metadata_update_issue_form(input: dict):
        name = convert_to_kebab_case(mapFromRequired(input, "Icon name"))
        metadata = load_metadata(name)
        
        return MonochromeIcon(
            None,
            None,
            name,
            metadata["base"],
            mapListFrom(input, "Categories"),
            mapListFrom(input, "Aliases")
        )

def checkType(type: str):
    if type not in ["normal", "monochrome"]:
        raise ValueError(f"Invalid icon type: '{type}'")
    return type

def checkAction(action: str):
    if action == "addition":
        return IssueFormType.ADDITION
    elif action == "update":
        return IssueFormType.UPDATE
    elif action == "metadata_update":
        return IssueFormType.METADATA_UPDATE
    raise ValueError(f"Invalid action: '{action}'")

class IssueFormType(Enum):
    ADDITION = "addition"
    UPDATE = "update"
    METADATA_UPDATE = "metadata_update"

def iconFactory(type: str, issue_form: str, issue_form_type: IssueFormType):
    if type == "normal":
        if (issue_form_type == IssueFormType.ADDITION):
            return NormalIcon.from_addition_issue_form(json.loads(issue_form))
        elif (issue_form_type == IssueFormType.UPDATE):
            return NormalIcon.from_update_issue_form(json.loads(issue_form))
        elif (issue_form_type == IssueFormType.METADATA_UPDATE):
            return NormalIcon.from_metadata_update_issue_form(json.loads(issue_form))
        else:
            raise ValueError(f"Invalid issue form type: '{issue_form_type}'")
    elif type == "monochrome":
        if (issue_form_type == IssueFormType.ADDITION):
            return MonochromeIcon.from_addition_issue_form(json.loads(issue_form))
        elif (issue_form_type == IssueFormType.UPDATE):
            return MonochromeIcon.from_update_issue_form(json.loads(issue_form))
        elif (issue_form_type == IssueFormType.METADATA_UPDATE):
            return MonochromeIcon.from_metadata_update_issue_form(json.loads(issue_form))
        else:
            raise ValueError(f"Invalid issue form type: '{issue_form_type}'")
    raise ValueError(f"Invalid icon type: '{type}'")

def mapFrom(input: dict, label: str) -> str:
        return input.get(label, None)

def mapFromRequired(input: dict, label: str) -> str:
    value = mapFrom(input, label)
    if value is None:
        raise ValueError(f"Missing required field: '{label}'")
    return value

def mapFileTypeFrom(input: dict, label: str) -> str:
    fileType = mapFromRequired(input, label)
    if fileType not in ["SVG", "PNG"]:
        raise ValueError(f"Invalid file type: '{fileType}'")
    return fileType.lower()

def mapListFrom(input: dict, label: str) -> list:
    stringList = mapFrom(input, label)
    if stringList is None:
        return []
    return list(map(str.strip, stringList.split(",")))

def mapUrlFromMarkdownImage(input: dict, label: str) -> re.Match[str]:
    markdown = mapFromRequired(input, label)
    try:
        return re.match(r"!\[[^\]]+\]\((https:[^\)]+)\)", markdown)[1]
    except IndexError:
        raise ValueError(f"Invalid markdown image: '{markdown}'")