from StageHubAPI import db

from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship

# from dataclasses import dataclass
import datetime
import hashlib


class Studio(db.Model):
    __tablename__ = 'studio'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String)  # Studio Name
    code_name = db.Column(db.String(64))  # cgtp, cgxm, bgs
    description = db.Column(db.Text)
    image_id = db.Column(db.Integer, default=0)
    type = db.Column(db.String(32))  # internal, outsource, client
    meta_data = db.Column(db.Text)

    def __repr__(self):
        return f"<{type(self).__name__}(name='{self.name}')>"


# @dataclass
class Project(db.Model):
    # id: int
    # name: str
    # code_name: str
    # description: str
    # type: str
    # vendor: str
    # image_id: int
    # enabled: bool

    __tablename__ = 'project'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String)
    code_name = db.Column(db.String(64))
    description = db.Column(db.Text)
    type = db.Column(db.String(64), default='tv')
    vendor_id = db.Column(db.Integer, ForeignKey('vendor.id'), nullable=True)
    vendor = relationship('Vendor', back_populates='projects')
    image_id = db.Column(db.Integer, default=0)
    enabled = db.Column(db.Boolean, default=True)
    parent_id = db.Column(db.Integer, nullable=True)
    create_on = db.Column(db.DateTime, default=datetime.datetime.now)
    update_on = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now,  nullable=False)
    private = db.Column(db.Boolean, default=False)
    central_id = db.Column(db.Integer, ForeignKey('studio.id'), nullable=True)
    studio_id = db.Column(db.Integer, ForeignKey('studio.id'), nullable=True)

    def __repr__(self):
        return f"<{type(self).__name__}(name='{self.name}')>"


class Vendor(db.Model):
    __tablename__ = 'vendor'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String)
    code_name = db.Column(db.String(64))
    description = db.Column(db.Text)
    projects = relationship('Project')

    def __repr__(self):
        return f"<{type(self).__name__}(name='{self.name}')>"


class ProjectDrive(db.Model):
    __tablename__ = 'project_drive'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    project_id = db.Column(db.Integer, ForeignKey('project.id'))
    studio_id = db.Column(db.Integer, ForeignKey('studio.id'))
    platform = db.Column(db.String(10))  # win32, linux, macosx
    type = db.Column(db.String, nullable=False)  # data, image
    data_server = db.Column(db.String)
    data_source = db.Column(db.String)
    filesystem = db.Column(db.String)  # samba, nfs
    mount_point = db.Column(db.String)

    def __repr__(self):
        return f"<{type(self).__name__}>"


class AssetCategory(db.Model):
    __tablename__ = 'asset_category'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(32))
    parent_id = db.Column(db.Integer)
    description = db.Column(db.Text)

    def __repr__(self):
        return f"<{type(self).__name__}(name='{self.name}')>"


class Asset(db.Model):
    __tablename__ = 'asset'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    project_id = db.Column(db.Integer)
    image_id = db.Column(db.Integer, default=0)
    type = db.Column(db.String(32))  # char, prop, set
    name = db.Column(db.String(64))
    parent_id = db.Column(db.Integer)
    description = db.Column(db.Text)
    meta_data = db.Column(db.Text)
    enabled = db.Column(db.Boolean, default=True)

    def __repr__(self):
        return f"<{type(self).__name__}(name='{self.name}')>"


class Episode(db.Model):
    __tablename__ = 'episode'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(32))
    project_id = db.Column(db.Integer, ForeignKey('project.id'))

    def __repr__(self):
        return f"<{type(self).__name__}(name='{self.name}')>"


class Stage(db.Model):
    __tablename__ = 'stage'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    # modeling, surfacing, rigging, matte_painting, layout, animation, lighting, compositing
    name = db.Column(db.String(64))
    # MDL, SFC, RIG, DMP, CFX_HAIR, CFX_XGEN, LAY, SIM, FX, DRS, LGT, COMP
    code_name = db.Column(db.String(64))
    parent_id = db.Column(db.Integer, nullable=True)  # Parent stage id
    type = db.Column(db.String(64))  # asset, shot
    description = db.Column(db.Text)


class Step(db.Model):
    __tablename__ = 'step'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    # Primary, Secondary, Animation, Blocking
    name = db.Column(db.String(64))
    # PRI, SEC, ANI, BLK
    code_name = db.Column(db.String(64))
    parent_id = db.Column(db.Integer, nullable=True)  # Parent step id
    description = db.Column(db.Text)


class ProjectStage(db.Model):
    __tablename__ = 'project_stage'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    project_id = db.Column(db.Integer, ForeignKey('project.id'))
    stage_id = db.Column(db.Integer, ForeignKey('stage.id'))
    steps = relationship('ProjectStep')


class ProjectStep(db.Model):
    __tablename__ = 'project_step'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    project_stage_id = db.Column(db.Integer, ForeignKey('project_stage.id'))
    project_stage = relationship('ProjectStage', back_populates='steps')
    step_id = db.Column(db.Integer, ForeignKey('step.id'))


class ProjectGroup(db.Model):
    __tablename__ = 'project_group'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    project_id = db.Column(db.Integer, ForeignKey('project.id'))
    group_id = db.Column(db.Integer, ForeignKey('group.id'))


class Status(db.Model):
    __tablename__ = 'status'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String)
    description = db.Column(db.Text)

    def __repr__(self):
        return f"<{type(self).__name__}(name='{self.name}')>"


class Shot(db.Model):
    __tablename__ = 'shot'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    project_id = db.Column(db.Integer, ForeignKey('project.id'))
    name = db.Column(db.String)
    type = db.Column(db.String(10))  # main, screen, option
    status = db.Column(db.String(10))  # pending, wip, approve
    stage = db.Column(db.String(20))
    image_id = db.Column(db.Integer, default=0)  # thumbnil
    reuse_id = db.Column(db.Integer, nullable=True)  # Reuse shot id
    parent_id = db.Column(db.Integer)
    timecode = db.Column(db.String)
    description = db.Column(db.Text)
    meta_data = db.Column(db.Text)
    enabled = db.Column(db.Boolean, default=True)

    def __repr__(self):
        return f"<{type(self).__name__}(name='{self.name}')>"


class ShotStage(db.Model):
    __tablename__ = 'shot_stage'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    shot_id = db.Column(db.Integer, ForeignKey('shot.id'))
    stage_id = db.Column(db.Integer, ForeignKey('stage.id'))


class ShotEpisode(db.Model):
    __tablename__ = 'shot_episode'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    shot_id = db.Column(db.Integer)
    episode_id = db.Column(db.Integer)


class ShotCategory(db.Model):
    __tablename__ = 'shot_category'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    shot_id = db.Column(db.Integer)
    category_id = db.Column(db.Integer)


class Category(db.Model):
    __tablename__ = 'category'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String)
    entry_type = db.Column(db.String(64))  # shot, asset
    type = db.Column(db.String(64))  # act, sequence
    parent_id = db.Column(db.Integer)
    description = db.Column(db.Text)

    def __repr__(self):
        return f"<{type(self).__name__}(name='{self.name}')>"


class TaskStatus(db.Model):
    __tablename__ = 'task_status'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String)
    description = db.Column(db.Text)

    def __repr__(self):
        return f"<{type(self).__name__}(name='{self.name}')>"


class Task(db.Model):
    __tablename__ = 'task'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    source_id = db.Column(db.Integer)  # source_id
    type = db.Column(db.String(20))  # asset, shot
    name = db.Column(db.String(30))  # task name, usually same as stage name
    stage = db.Column(db.String(30))  # modeling, surfacing, layout, animation, lighting, simulation, fx, compositing
    step = db.Column(db.String(30), default='', nullable=True)  # Ani, Pri, Sec
    description = db.Column(db.Text)
    parent_id = db.Column(db.Integer)  # parent task id
    status = db.Column(db.String(64))
    author_id = db.Column(db.Integer, ForeignKey('account.id'))
    start_date = db.Column(db.Date)
    end_date = db.Column(db.Date)
    assign_to = db.Column(db.Integer, ForeignKey('account.id'))  # account id assign to
    create_on = db.Column(db.DateTime, default=datetime.datetime.now)
    update_on = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
    private = db.Column(db.Boolean, default=False)  # only author and assignee can see it
    percent = db.Column(db.Integer, default=0)  # progress percentage (0-100%)
    use_check_list = db.Column(db.Boolean, default=False)
    check_list = relationship('CheckList')
    attachment = relationship('Attachment')
    active = db.Column(db.Boolean, default=True)

    def __repr__(self):
        return f"<{type(self).__name__}(type='{self.type}', name='self.name')>"


class CheckList(db.Model):
    __tablename__ = 'check_list'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String)
    checked = db.Column(db.Boolean, default=False)
    task_id = db.Column(db.Integer, ForeignKey('task.id'))
    task = relationship("Task", back_populates="check_list")

    def __repr__(self):
        return f"<{type(self).__name__}(type='{self.type}', name='self.name')>"


class ShotDelivery(db.Model):
    __tablename__ = 'shot_delivery'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    author_id = db.Column(db.Integer, ForeignKey('account.id'))
    delivery_to = db.Column(db.Integer, ForeignKey('account.id'))
    create_on = db.Column(db.DateTime, default=datetime.datetime.now)
    note_id = db.Column(db.Integer, ForeignKey('note.id'))
    attachment_id = db.Column(db.Integer, ForeignKey('attachment.id'))
    content_path = db.Column(db.String(255))
    description = db.Column(db.Text)
    meta_data = db.Column(db.Text)

    def __repr__(self):
        return f"<{type(self).__name__}(type='{self.type}', name='self.name')>"


class Account(db.Model):
    __tablename__ = 'account'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    login = db.Column(db.String(64))
    image_id = db.Column(db.Integer, ForeignKey('image.id'), nullable=True)
    first_name = db.Column(db.String(64))
    last_name = db.Column(db.String(64))
    type = db.Column(db.String(10))  # inhouse, external, client, api
    studio_id = db.Column(db.String(64), ForeignKey('studio.id'), nullable=True)  # studio name
    mail = db.Column(db.String(255))
    password = db.Column(db.String(255))
    auth_type = db.Column(db.Integer, default=0)  # 0: internal, 1: LDAP
    admin = db.Column(db.Boolean, default=False)
    create_on = db.Column(db.DateTime, default=datetime.datetime.now)
    update_on = db.Column(db.DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
    last_login = db.Column(db.DateTime)
    use_expire = db.Column(db.Boolean, default=False)
    expire_on = db.Column(db.DateTime)
    locked = db.Column(db.Boolean, default=False)
    activate = db.Column(db.Boolean, default=True)
    token = db.Column(db.String(255))
    description = db.Column(db.Text)
    meta_data = db.Column(db.Text)

    def __repr__(self):
        return f"<{type(self).__name__}(login={self.name})>"


class Group(db.Model):
    __tablename__ = 'group'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String(64))
    type = db.Column(db.String(16))  # department, notify, watch
    public = db.Column(db.Boolean, default=True)
    description = db.Column(db.Text)

    def __repr__(self):
        return f"<{type(self).__name__}(login={self.name})>"


class AccountGroup(db.Model):
    __tablename__ = 'account_group'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    account_id = db.Column(db.Integer)
    group_id = db.Column(db.Integer)

    def __repr__(self):
        return f"<{type(self).__name__}>"


class Membership(db.Model):
    __tablename__ = 'membership'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    name = db.Column(db.String)

    def __repr__(self):
        return f"<{type(self).__name__}>"


class Permission(db.Model):
    __tablename__ = 'permission'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    memership_id = db.Column(db.Integer)

    view_project = db.Column(db.Boolean)
    create_project = db.Column(db.Boolean)
    edit_project = db.Column(db.Boolean)
    delete_project = db.Column(db.Boolean)

    create_asset = db.Column(db.Boolean)
    view_asset = db.Column(db.Boolean)
    edit_asset = db.Column(db.Boolean)
    publish_asset = db.Column(db.Boolean)
    delete_asset = db.Column(db.Boolean)

    view_shot = db.Column(db.Boolean)
    create_shot = db.Column(db.Boolean)
    edit_shot = db.Column(db.Boolean)
    publish_shot = db.Column(db.Boolean)
    delete_shot = db.Column(db.Boolean)

    create_asset_task = db.Column(db.Boolean)
    view_asset_task = db.Column(db.Boolean)
    edit_asset_task = db.Column(db.Boolean)
    delete_asset_task = db.Column(db.Boolean)

    create_shot_task = db.Column(db.Boolean)
    view_shot_task = db.Column(db.Boolean)
    edit_shot_task = db.Column(db.Boolean)
    delete_shot_task = db.Column(db.Boolean)

    create_note = db.Column(db.Boolean)
    view_note = db.Column(db.Boolean)
    edit_note = db.Column(db.Boolean)
    delete_note = db.Column(db.Boolean)

    create_attachment = db.Column(db.Boolean)
    view_attachment = db.Column(db.Boolean)
    edit_attachment = db.Column(db.Boolean)
    delete_attachment = db.Column(db.Boolean)

    notify = db.Column(db.Boolean)

    def __repr__(self):
        return f"<{type(self).__name__}>"


class Attachment(db.Model):
    __tablename__ = 'attachment'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    filename = db.Column(db.String(255))
    file_size = db.Column(db.BigInteger)
    disk_filename = db.Column(db.String(255))
    disk_directory = db.Column(db.String(255))
    content_type = db.Column(db.String(255))
    digest = db.Column(db.String(64))
    author_id = db.Column(db.Integer)
    created_date = db.Column(db.DateTime)
    description = db.Column(db.Text)
    task_id = db.Column(db.Integer, ForeignKey('task.id'))

    def __repr__(self):
        return f"<{type(self).__name__}(filename='{self.filename}')>"


class Image(db.Model):
    __tablename__ = 'image'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    filename = db.Column(db.String(255))
    hash = db.Column(db.String(255))
    file_size = db.Column(db.BigInteger)
    disk_filename = db.Column(db.String(255))
    width = db.Column(db.Integer)
    height = db.Column(db.Integer)
    created_date = db.Column(db.DateTime)


class Note(db.Model):
    __tablename__ = 'note'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    entry_type = db.Column(db.String)  # asset, shot
    entry_id = db.Column(db.Integer)  # asset_id, shot_id
    attatch_id = db.Column(db.Integer, nullable=True)
    enabled = db.Column(db.Boolean)
    rich = db.Column(db.Boolean)  # rich format
    text = db.Column(db.Text)
