import uuid
from datetime import datetime
from typing import Dict, List, Optional, Any
from sqlalchemy import Column, ForeignKey, Integer, String, Boolean, func
from sqlalchemy.orm import relationship, Mapped, mapped_column

from db.models.base import Base, BaseMixin


class Publisher(Base):
    __tablename__ = "publisher"
    id: Mapped[str] = mapped_column(primary_key=True, default=uuid.uuid4)
    created_date: Mapped[datetime] = mapped_column(default=func.now())
    last_modified_date: Mapped[datetime] = mapped_column(default=func.now())
    version: Mapped[int] = mapped_column(default=0)
    name = Column(String, unique=True)
    weblink = Column(String, nullable=True)
    parent_publisher_id: Mapped[Optional[str]] = mapped_column(ForeignKey('publisher.id'))
    parent_publisher: Mapped[Optional['Publisher']] = relationship("Publisher", back_populates="imprints", remote_side=[id])
    imprints: Mapped[List['Publisher']] = relationship('Publisher', back_populates="parent_publisher")
    comics = relationship("Comic")

    def __repr__(self):
        return f'Publisher({self.id} {self.name})'

    def __str__(self):
        return self.__repr__()

    def import_dict(self, import_data: Dict[str, Any]):
        self.id = import_data['id']
        self.created_date = import_data['created_date']
        self.last_modified_date = import_data['last_modified_date']
        self.version = import_data['version']
        self.name = import_data['name']
        self.parent_publisher_id = import_data['parent_publisher_id']

    def export_dict(self) -> Dict[str, Any]:
        item: Dict[str, Any] = {
            'id': self.id,
            'created_date': str(self.created_date),
            'last_modified_date': str(self.last_modified_date),
            'version': self.version,
            'name': self.name,
            'weblink': self.weblink,
            'parent_publisher_id': self.parent_publisher_id
        }
        return item


class Comic(Base, BaseMixin):
    __tablename__ = 'comic'
    title = Column(String, unique=True)
    publisher_id = Column(String, ForeignKey('publisher.id'), nullable=False)
    publisher = relationship("Publisher", back_populates="comics")
    current_order = Column(Boolean)
    completed = Column(Boolean)
    weblink = Column(String, nullable=True)
    issues = relationship("Issue")
    story_arcs = relationship("StoryArc")
    trade_paperbacks = relationship("TradePaperback")
    volumes = relationship("Volume")
    comic_works = relationship("ComicWork")

    def __repr__(self):
        return f'Comic({self.id} {self.version} {self.title} {self.publisher.name})'

    def __str__(self):
        return f'{self.title}({self.id})'

    def import_dict(self, import_data: Dict[str, Any]):
        self.id = import_data['id']
        self.created_date = import_data['created_date']
        self.last_modified_date = import_data['last_modified_date']
        self.version = import_data['version']
        self.title = import_data['title']
        self.publisher_id = import_data['publisher_id']
        self.current_order = import_data['current_order']
        self.completed = import_data['completed']
        if 'weblink' in import_data:
            self.weblink = import_data['weblink']

    def export_dict(self) -> Dict[str, Any]:
        item: Dict[str, Any] = {
            'id': self.id,
            'created_date': str(self.created_date),
            'last_modified_date': str(self.last_modified_date),
            'version': self.version,
            'title': self.title,
            'publisher_id': self.publisher_id,
            'current_order': self.current_order,
            'completed': self.completed,
            'weblink': self.weblink
        }
        return item


class Volume(Base, BaseMixin):
    __tablename__ = "volume"
    name = Column(String, nullable=False)
    comic_id = Column(String, ForeignKey("comic.id"), nullable=False)
    comic = relationship("Comic", back_populates="volumes")
    story_arcs = relationship("StoryArc")
    issues = relationship("Issue")

    def import_dict(self, import_data: Dict[str, Any]):
        self.id = import_data['id']
        self.created_date = import_data['created_date']
        self.last_modified_date = import_data['last_modified_date']
        self.version = import_data['version']
        self.name = import_data['name']
        self.comic_id = import_data['comic_id']

    def export_dict(self) -> Dict[str, Any]:
        item: Dict[str, Any] = {}
        item['id'] = self.id
        item['created_date'] = str(self.created_date)
        item['last_modified_date'] = str(self.last_modified_date)
        item['version'] = self.version
        item['name'] = self.name
        item['comic_id'] = self.comic_id
        return item

class TradePaperback(Base, BaseMixin):
    __tablename__ = "trade_paperback"
    name = Column(String, nullable=False)
    issue_start = Column(Integer)
    issue_end = Column(Integer)
    comic_id = Column(String, ForeignKey("comic.id"), nullable=False)
    comic = relationship("Comic", back_populates="trade_paperbacks")

    def import_dict(self, import_data: Dict[str, Any]):
        self.id = import_data['id']
        self.created_date = import_data['created_date']
        self.last_modified_date = import_data['last_modified_date']
        self.version = import_data['version']
        self.name = import_data['name']
        self.issue_start = import_data['issue_start']
        self.issue_end = import_data['issue_end']
        self.comic_id = import_data['comic_id']

    def export_dict(self) -> Dict[str, Any]:
        item: Dict[str, Any] = {}
        item['id'] = self.id
        item['created_date'] = str(self.created_date)
        item['last_modified_date'] = str(self.last_modified_date)
        item['version'] = self.version
        item['name'] = self.name
        item['issue_start'] = self.issue_start
        item['issue_end'] = self.issue_end
        item['comic_id'] = self.comic_id
        return item


class StoryArc(Base, BaseMixin):
    __tablename__ = "story_arc"
    name = Column(String, nullable=False)
    comic_id = Column(String, ForeignKey("comic.id"), nullable=False)
    comic = relationship("Comic", back_populates="story_arcs")
    volume_id = Column(String, ForeignKey("volume.id"), nullable=True)
    volume = relationship("Volume", back_populates="story_arcs")
    issues = relationship("Issue")

    def import_dict(self, import_data: Dict[str, Any]):
        self.id = import_data['id']
        self.created_date = import_data['created_date']
        self.last_modified_date = import_data['last_modified_date']
        self.version = import_data['version']
        self.name = import_data['name']
        self.comic_id = import_data['comic_id']
        self.volume_id = import_data['volume_id']

    def export_dict(self) -> Dict[str, Any]:
        item: Dict[str, Any] = {
            'id': self.id,
            'created_date': str(self.created_date),
            'last_modified_date': str(self.last_modified_date),
            'version': self.version,
            'name': self.name,
            'comic_id': self.comic_id,
            'volume_id': self.volume_id
        }
        return item


class Issue(Base, BaseMixin):
    __tablename__ = "issue"
    issue_number = Column(String)
    title = Column(String, nullable=True)
    published_on: Mapped[datetime] = mapped_column(nullable=True)
    in_stock = Column(Boolean)
    is_read = Column(Boolean)
    comic_id = Column(String, ForeignKey("comic.id"), nullable=False)
    comic = relationship("Comic", back_populates="issues")
    volume_id = Column(String, ForeignKey("volume.id"), nullable=True)
    volume = relationship("Volume", back_populates="issues")
    story_arc_id = Column(String, ForeignKey("story_arc.id"), nullable=True)
    story_arc = relationship("StoryArc", back_populates="issues")
    issue_works = relationship("IssueWork")

    def import_dict(self, import_data: Dict[str, Any]):
        self.id = import_data['id']
        self.created_date = import_data['created_date']
        self.last_modified_date = import_data['last_modified_date']
        self.version = import_data['version']
        self.issue_number = import_data['issue_number']
        self.title = import_data['title']
        if import_data['published_on'] == 'None':
            self.published_on = None # type: ignore
        else:
            self.published_on = import_data['published_on']
        self.in_stock = import_data['in_stock']
        self.is_read = import_data['is_read']
        self.comic_id = import_data['comic_id']
        self.volume_id = import_data['volume_id']
        self.story_arc_id = import_data['story_arc_id']

    def export_dict(self) -> Dict[str, Any]:
        item: Dict[str, Any] = {
            'id': self.id,
            'created_date': str(self.created_date),
            'last_modified_date': str(self.last_modified_date),
            'version': self.version,
            'issue_number': self.issue_number,
            'title': self.title,
            'published_on': str(self.published_on),
            'in_stock': self.in_stock,
            'is_read': self.is_read,
            'comic_id': self.comic_id,
            'volume_id': self.volume_id,
            'story_arc_id': self.story_arc_id
        }
        return item


class Artist(Base, BaseMixin):
    __tablename__ = "artist"
    name = Column(String, nullable=False)
    weblink = Column(String, nullable=True)
    comic_works = relationship("ComicWork")
    issue_works = relationship("IssueWork")

    def import_dict(self, import_data: Dict[str, Any]):
        self.id = import_data['id']
        self.created_date = import_data['created_date']
        self.last_modified_date = import_data['last_modified_date']
        self.version = import_data['version']
        self.name = import_data['name']
        if 'weblink' in import_data:
            self.weblink = import_data['weblink']

    def export_dict(self) -> Dict[str, Any]:
        item: Dict[str, Any] = {
            'id': self.id,
            'created_date': str(self.created_date),
            'last_modified_date': str(self.last_modified_date),
            'version': self.version,
            'name': self.name,
            'weblink': self.weblink
        }
        return item


class WorkType(Base, BaseMixin):
    __tablename__ = "worktype"
    name = Column(String, nullable=False, unique=True)
    comic_works = relationship("ComicWork")
    issue_works = relationship("IssueWork")

    def __repr__(self):
        return f'Worktype({self.id} {self.version} {self.name} {len(self.comic_works)})'

    def __str__(self):
        return f'{self.name}({self.id})'

    def import_dict(self, import_data: Dict[str, Any]):
        self.id = import_data['id']
        self.created_date = import_data['created_date']
        self.last_modified_date = import_data['last_modified_date']
        self.version = import_data['version']
        self.name = import_data['name']

    def export_dict(self) -> Dict[str, Any]:
        item: Dict[str, Any] = {
            'id': self.id,
            'created_date': str(self.created_date),
            'last_modified_date': str(self.last_modified_date),
            'version': self.version,
            'name': self.name
        }
        return item


class ComicWork(Base, BaseMixin):
    __tablename__ = "comic_work"
    comic_id = Column(String, ForeignKey("comic.id"), nullable=False)
    comic = relationship("Comic", back_populates="comic_works")
    artist_id = Column(String, ForeignKey("artist.id"), nullable=False)
    artist = relationship("Artist", back_populates="comic_works")
    work_type_id = Column(String, ForeignKey("worktype.id"), nullable=False)
    work_type = relationship("WorkType", back_populates="comic_works")

    def import_dict(self, import_data: Dict[str, Any]):
        self.id = import_data['id']
        self.created_date = import_data['created_date']
        self.last_modified_date = import_data['last_modified_date']
        self.version = import_data['version']
        self.comic_id = import_data['comic_id']
        self.artist_id = import_data['artist_id']
        self.work_type_id = import_data['work_type_id']

    def export_dict(self) -> Dict[str, Any]:
        item: Dict[str, Any] = {
            'id': self.id,
            'created_date': str(self.created_date),
            'last_modified_date': str(self.last_modified_date),
            'version': self.version,
            'comic_id': self.comic_id,
            'artist_id': self.artist_id,
            'work_type_id': self.work_type_id
        }
        return item


class IssueWork(Base, BaseMixin):
    __tablename__ = "issue_work"
    issue_id = Column(String, ForeignKey("issue.id"), nullable=False)
    issue = relationship("Issue", back_populates="issue_works")
    artist_id = Column(String, ForeignKey("artist.id"), nullable=False)
    artist = relationship("Artist", back_populates="issue_works")
    work_type_id = Column(String, ForeignKey("worktype.id"), nullable=False)
    work_type = relationship("WorkType", back_populates="issue_works")

    def import_dict(self, import_data: Dict[str, Any]):
        self.id = import_data['id']
        self.created_date = import_data['created_date']
        self.last_modified_date = import_data['last_modified_date']
        self.version = import_data['version']
        self.issue_id = import_data['issue_id']
        self.artist_id = import_data['artist_id']
        self.work_type_id = import_data['work_type_id']

    def export_dict(self) -> Dict[str, Any]:
        item: Dict[str, Any] = {
            'id': self.id,
            'created_date': str(self.created_date),
            'last_modified_date': str(self.last_modified_date),
            'version': self.version,
            'issue_id': self.issue_id,
            'artist_id': self.artist_id,
            'work_type_id': self.work_type_id
        }
        return item
