from typing import Optional
import datetime
import uuid

from sqlalchemy import (ARRAY, Boolean, DateTime, Double, Enum, ForeignKeyConstraint, Index, Integer, JSON, PrimaryKeyConstraint, String, Time, UniqueConstraint, Uuid, text, Sequence, func)
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship

class Base(DeclarativeBase):
    pass


class Company(Base):
    __tablename__ = 'company'
    __table_args__ = (
        PrimaryKeyConstraint('id', name='company_pk'),
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    url: Mapped[Optional[str]] = mapped_column(String(255))
    created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now())
    updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now(), onupdate=func.now())

    team: Mapped[list['Team']] = relationship('Team', back_populates='company')


class Product(Base):
    __tablename__ = 'product'
    __table_args__ = (
        PrimaryKeyConstraint('id', name='product_pk'),
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
    name: Mapped[str] = mapped_column(String(32), nullable=False)
    app_id: Mapped[Optional[str]] = mapped_column(String(16))
    scope: Mapped[Optional[dict]] = mapped_column(JSON)
    description: Mapped[Optional[str]] = mapped_column(String(256))
    created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now())
    updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now(), onupdate=func.now())

    robeing: Mapped[list['Robeing']] = relationship('Robeing', back_populates='product')


class Team(Base):
    __tablename__ = 'team'
    __table_args__ = (
        ForeignKeyConstraint(['company_id'], ['company.id'], name='team_company_id_fk'),
        PrimaryKeyConstraint('id', name='team_pk')
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
    company_id: Mapped[uuid.UUID] = mapped_column(Uuid, nullable=False)
    name: Mapped[str] = mapped_column(String(32), nullable=False)
    is_default: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=Boolean(False))
    created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now())
    updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now(), onupdate=func.now())

    company: Mapped['Company'] = relationship('Company', back_populates='team')
    robeing: Mapped[list['Robeing']] = relationship('Robeing', back_populates='team')
    slack_workspace: Mapped[list['SlackWorkspace']] = relationship('SlackWorkspace', back_populates='team')
    user: Mapped[list['User']] = relationship('User', back_populates='team')


class Robeing(Base):
    __tablename__ = 'robeing'
    __table_args__ = (
        ForeignKeyConstraint(['product_id'], ['product.id'], name='robeing_product_id_fk'),
        ForeignKeyConstraint(['team_id'], ['team.id'], name='robeing_team_id_fk'),
        PrimaryKeyConstraint('id', name='robeing_pk')
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
    product_id: Mapped[uuid.UUID] = mapped_column(Uuid, nullable=False)
    team_id: Mapped[uuid.UUID] = mapped_column(Uuid, nullable=False)
    name: Mapped[Optional[str]] = mapped_column(String(32))
    level: Mapped[Optional[int]] = mapped_column(Integer, server_default=Integer(1))
    experience: Mapped[Optional[int]] = mapped_column(Integer, server_default=Integer(0))
    memory: Mapped[Optional[int]] = mapped_column(Integer, server_default=Integer(10))
    compute: Mapped[Optional[int]] = mapped_column(Integer, server_default=Integer(10))
    react: Mapped[Optional[int]] = mapped_column(Integer, server_default=Integer(10))
    empathy: Mapped[Optional[int]] = mapped_column(Integer, server_default=Integer(10))
    leadership: Mapped[Optional[int]] = mapped_column(Integer, server_default=Integer(10))
    updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now(), onupdate=func.now())
    created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now())
    robeing_container_id: Mapped[Optional[str]] = mapped_column(String(64))
    robeing_container_url: Mapped[Optional[str]] = mapped_column(String(128))

    product: Mapped['Product'] = relationship('Product', back_populates='robeing')
    team: Mapped['Team'] = relationship('Team', back_populates='robeing')


class SlackWorkspace(Base):
    __tablename__ = 'slack_workspace'
    __table_args__ = (
        ForeignKeyConstraint(['team_id'], ['team.id'], name='slack_workspace_team_id_fk'),
        PrimaryKeyConstraint('id', name='slack_workspace_pk')
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
    team_id: Mapped[uuid.UUID] = mapped_column(Uuid, nullable=False)
    slack_team_id: Mapped[Optional[str]] = mapped_column(String(32))
    bot_token: Mapped[Optional[str]] = mapped_column(String(255))
    is_enterprise_install: Mapped[Optional[bool]] = mapped_column(Boolean, server_default=Boolean(True))
    is_active: Mapped[Optional[bool]] = mapped_column(Boolean)
    installed_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now())
    created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now())
    updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now(), onupdate=func.now())

    team: Mapped['Team'] = relationship('Team', back_populates='slack_workspace')


class User(Base):
    __tablename__ = 'user'
    __table_args__ = (
        ForeignKeyConstraint(['team_id'], ['team.id'], name='user_team_id_fk'),
        PrimaryKeyConstraint('id', name='user_pk'),
        UniqueConstraint('email', name='users_email_key')
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
    team_id: Mapped[uuid.UUID] = mapped_column(Uuid, nullable=False)
    email: Mapped[str] = mapped_column(String(255), nullable=False)
    username: Mapped[Optional[str]] = mapped_column(String(64))
    name: Mapped[Optional[str]] = mapped_column(String(255))
    picture: Mapped[Optional[str]] = mapped_column(String(500))
    oauth_provider: Mapped[Optional[str]] = mapped_column(String(50))
    oauth_id: Mapped[Optional[str]] = mapped_column(String(255))
    is_active: Mapped[Optional[bool]] = mapped_column(Boolean)
    is_admin: Mapped[bool] = mapped_column(Boolean, nullable=False, server_default=Boolean(False))
    last_login_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True))
    created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now())
    updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now(), onupdate=func.now())

    team: Mapped['Team'] = relationship('Team', back_populates='user')
    conversation_log: Mapped[list['ConversationLog']] = relationship('ConversationLog', back_populates='user')
    gmail_token: Mapped[list['GmailToken']] = relationship('GmailToken', back_populates='user')
    news: Mapped[list['News']] = relationship('News', back_populates='user')
    user_preference: Mapped[list['UserPreference']] = relationship('UserPreference', back_populates='user')
    workspace_member: Mapped[list['WorkspaceMember']] = relationship('WorkspaceMember', back_populates='user')


class ConversationLog(Base):
    __tablename__ = 'conversation_log'
    __table_args__ = (
        ForeignKeyConstraint(['user_id'], ['user.id'], name='conversation_log_user_id'),
        PrimaryKeyConstraint('id', name='conversation_log_pk')
    )

    id: Mapped[int] = mapped_column(Integer, Sequence('conversation_log_id_seq'), primary_key=True)
    user_id: Mapped[uuid.UUID] = mapped_column(Uuid, nullable=False)
    channel_id: Mapped[Optional[str]] = mapped_column(String(16))
    message: Mapped[Optional[str]] = mapped_column(String)
    response: Mapped[Optional[str]] = mapped_column(String)
    intent: Mapped[Optional[str]] = mapped_column(String(256))
    confidence: Mapped[Optional[float]] = mapped_column(Double(53))
    thread_ts: Mapped[Optional[str]] = mapped_column(String(128))
    timestamp: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True))
    channel_type: Mapped[Optional[str]] = mapped_column(String(32))

    user: Mapped['User'] = relationship('User', back_populates='conversation_log')


class GmailToken(Base):
    __tablename__ = 'gmail_token'
    __table_args__ = (
        ForeignKeyConstraint(['user_id'], ['user.id'], name='user_id_fk'),
        PrimaryKeyConstraint('id', name='gmail_token_pk'),
        Index('idx_gmail_token_oauth_config', 'oauth_config'),
        Index('idx_gmail_token_token_data', 'token_data')
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
    user_id: Mapped[uuid.UUID] = mapped_column(Uuid, nullable=False)
    token_data: Mapped[Optional[dict]] = mapped_column(JSONB)
    oauth_config: Mapped[Optional[dict]] = mapped_column(JSONB)
    scopes: Mapped[Optional[dict]] = mapped_column(JSONB)
    metadata_: Mapped[Optional[dict]] = mapped_column('metadata', JSONB)
    expiry: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime)
    is_equipped: Mapped[Optional[bool]] = mapped_column(Boolean, server_default=Boolean(False))
    equipped_to: Mapped[Optional[str]] = mapped_column(String(50))
    token_type: Mapped[Optional[str]] = mapped_column(String, server_default=text("'Bearer'::character varying"))
    expires_at: Mapped[Optional[float]] = mapped_column(Double(53))
    created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now())
    updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now(), onupdate=func.now())

    user: Mapped['User'] = relationship('User', back_populates='gmail_token')


class News(Base):
    __tablename__ = 'news'
    __table_args__ = (
        ForeignKeyConstraint(['user_id'], ['user.id'], name='news_user_id_fk'),
        PrimaryKeyConstraint('id', name='news_pk')
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
    user_id: Mapped[Optional[uuid.UUID]] = mapped_column(Uuid)
    data: Mapped[Optional[dict]] = mapped_column(JSONB)
    created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now())
    updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now(), onupdate=func.now())

    user: Mapped[Optional['User']] = relationship('User', back_populates='news')


class UserPreference(Base):
    __tablename__ = 'user_preference'
    __table_args__ = (
        ForeignKeyConstraint(['user_id'], ['user.id'], name='user_preference_user_id_fk'),
        PrimaryKeyConstraint('id', name='user_preference_pk')
    )

    user_id: Mapped[uuid.UUID] = mapped_column(Uuid, nullable=False)
    id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
    news_keywords: Mapped[Optional[list[str]]] = mapped_column(ARRAY(String(length=128)))
    email_filter: Mapped[Optional[list[str]]] = mapped_column(ARRAY(String(length=128)))
    briefing_enabled: Mapped[Optional[bool]] = mapped_column(Boolean, server_default=Boolean(True)) 
    briefing_time: Mapped[Optional[datetime.time]] = mapped_column(Time, server_default=text("'09:00:00'::time without time zone"))
    created_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now())
    updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime(True), server_default=func.now(), onupdate=func.now())

    user: Mapped['User'] = relationship('User', back_populates='user_preference')


class WorkspaceMember(Base):
    __tablename__ = 'workspace_member'
    __table_args__ = (
        ForeignKeyConstraint(['user_id'], ['user.id'], name='workspace_member_user_id_fkey'),
        PrimaryKeyConstraint('id', name='workspace_member_pk')
    )

    id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, default=uuid.uuid4)
    user_id: Mapped[uuid.UUID] = mapped_column(Uuid, nullable=False)
    slack_user_id: Mapped[Optional[str]] = mapped_column(String(32))
    role: Mapped[str] = mapped_column(Enum('OWNER', 'MEMBER', 'GUEST', name='user_role'), nullable=False, server_default=text("'GUEST'::user_role"))
    is_active: Mapped[Optional[bool]] = mapped_column(Boolean)
    joined_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime, server_default=func.now())
    updated_at: Mapped[Optional[datetime.datetime]] = mapped_column(DateTime, server_default=func.now())

    user: Mapped['User'] = relationship('User', back_populates='workspace_member')
