from sqlalchemy import create_engine, Column, Integer, String, Text, Boolean, Float, DateTime, ForeignKey, CheckConstraint, Index
from sqlalchemy.orm import declarative_base, relationship, sessionmaker
from datetime import datetime
from typing import Generator

Base = declarative_base()


class Customer(Base):
    __tablename__ = 'customers'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String(255), nullable=False, unique=True)
    keywords = Column(Text)
    git_repo = Column(String(500))
    contact = Column(String(255))
    status = Column(String(20), default='active')
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    
    projects = relationship("Project", back_populates="customer")
    processing_logs = relationship("ProcessingLog", back_populates="customer")


class Project(Base):
    __tablename__ = 'projects'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    customer_id = Column(Integer, ForeignKey('customers.id', ondelete='SET NULL'))
    name = Column(String(255), nullable=False)
    keywords = Column(Text)
    status = Column(String(20), default='planning')
    progress = Column(Integer, default=0)
    git_repo = Column(String(500))
    oc_collab_enabled = Column(Boolean, default=False)
    confidentiality = Column(String(20), default='normal')
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    
    customer = relationship("Customer", back_populates="projects")
    processing_logs = relationship("ProcessingLog", back_populates="project")
    bugs = relationship("Bug", back_populates="project")
    proposals = relationship("Proposal", back_populates="project")
    materials = relationship("Material", back_populates="project")
    templates = relationship("ProjectTemplate", back_populates="project")
    sync_status = relationship("ProjectSyncStatus", back_populates="project", uselist=False)
    sync_logs = relationship("SyncLog", back_populates="project")
    change_history = relationship("ChangeHistory", back_populates="project")


class ProcessingLog(Base):
    __tablename__ = 'processing_logs'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    input_type = Column(String(20), nullable=False)
    file_path = Column(String(500))
    content = Column(Text)
    extracted_text = Column(Text)
    dossierai_response = Column(Text)
    issue_type = Column(String(20))
    issue_id = Column(String(50))
    customer_id = Column(Integer, ForeignKey('customers.id', ondelete='SET NULL'))
    project_id = Column(Integer, ForeignKey('projects.id', ondelete='SET NULL'))
    result = Column(String(20), default='pending')
    error_message = Column(Text)
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    
    customer = relationship("Customer", back_populates="processing_logs")
    project = relationship("Project", back_populates="processing_logs")


class Bug(Base):
    __tablename__ = 'bugs'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    bug_id = Column(String(50), nullable=False, unique=True)
    project_id = Column(Integer, ForeignKey('projects.id', ondelete='CASCADE'), nullable=False)
    title = Column(String(255), nullable=False)
    description = Column(Text)
    severity = Column(String(5))
    status = Column(String(20), default='open')
    steps_to_reproduce = Column(Text)
    expected_behavior = Column(Text)
    actual_behavior = Column(Text)
    environment = Column(Text)
    assigned_to = Column(String(100))
    oc_git_commit_hash = Column(String(40))
    created_by = Column(String(50), default='PM-Agent')
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    resolved_at = Column(DateTime)
    
    project = relationship("Project", back_populates="bugs")


class Proposal(Base):
    __tablename__ = 'proposals'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    proposal_id = Column(String(50), nullable=False, unique=True)
    project_id = Column(Integer, ForeignKey('projects.id', ondelete='CASCADE'), nullable=False)
    title = Column(String(255), nullable=False)
    background = Column(Text)
    user_scenario = Column(Text)
    expected_behavior = Column(Text)
    priority = Column(String(10))
    status = Column(String(20), default='draft')
    estimated_hours = Column(Float)
    oc_git_commit_hash = Column(String(40))
    created_by = Column(String(50), default='PM-Agent')
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    implemented_at = Column(DateTime)
    
    project = relationship("Project", back_populates="proposals")


class Material(Base):
    __tablename__ = 'materials'
    
    id = Column(String(36), primary_key=True)
    project_id = Column(Integer, ForeignKey('projects.id', ondelete='SET NULL'))
    file_name = Column(String(255), nullable=False)
    file_type = Column(String(20), nullable=False)
    file_hash = Column(String(64), nullable=False)
    file_size = Column(Integer, nullable=False)
    storage_path = Column(String(500), nullable=False)
    status = Column(String(20), default='pending')
    issue_type = Column(String(20))
    issue_id = Column(String(50))
    raw_content = Column(Text)
    processed_content = Column(Text)
    template_id = Column(String(36))
    route_target = Column(String(500))
    route_history = Column(Text)
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    
    project = relationship("Project", back_populates="materials")


class ProjectTemplate(Base):
    __tablename__ = 'project_templates'
    
    id = Column(String(36), primary_key=True)
    project_id = Column(Integer, ForeignKey('projects.id', ondelete='CASCADE'), nullable=False)
    name = Column(String(255), nullable=False)
    template_type = Column(String(20), nullable=False)
    prompt_template = Column(Text, nullable=False)
    output_format = Column(String(20), default='markdown')
    fields = Column(Text, nullable=False)
    enabled = Column(Boolean, default=True)
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    
    project = relationship("Project", back_populates="templates")


class OperationLog(Base):
    __tablename__ = 'operation_logs'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    operation_type = Column(String(50), nullable=False)
    target_type = Column(String(50))
    target_id = Column(String(50))
    details = Column(Text)
    operator = Column(String(50), default='system')
    created_at = Column(DateTime, default=datetime.now)


class Setting(Base):
    __tablename__ = 'settings'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    key = Column(String(100), nullable=False, unique=True)
    value = Column(Text)
    description = Column(Text)
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)


class ProjectSyncStatus(Base):
    """项目同步状态 - v1.2.0新增"""
    __tablename__ = 'project_sync_status'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    project_id = Column(Integer, ForeignKey('projects.id', ondelete='CASCADE'), nullable=False)
    last_sync_time = Column(DateTime)
    sync_status = Column(String(20), default='ok')
    requirements_total = Column(Integer, default=0)
    requirements_completed = Column(Integer, default=0)
    requirements_in_progress = Column(Integer, default=0)
    bugs_total = Column(Integer, default=0)
    bugs_resolved = Column(Integer, default=0)
    todos_total = Column(Integer, default=0)
    todos_completed = Column(Integer, default=0)
    progress_percentage = Column(Integer, default=0)
    files_count = Column(Integer, default=0)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    
    project = relationship("Project", back_populates="sync_status")


class SyncLog(Base):
    """同步日志 - v1.2.0新增"""
    __tablename__ = 'sync_logs'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    project_id = Column(Integer, ForeignKey('projects.id', ondelete='CASCADE'), nullable=False)
    sync_type = Column(String(20), nullable=False)
    status = Column(String(20), default='success')
    files_synced = Column(Integer, default=0)
    files_added = Column(Integer, default=0)
    files_modified = Column(Integer, default=0)
    files_deleted = Column(Integer, default=0)
    error_message = Column(Text)
    started_at = Column(DateTime, default=datetime.now)
    completed_at = Column(DateTime)
    
    project = relationship("Project", back_populates="sync_logs")


class ChangeHistory(Base):
    """变更历史 - v1.2.0新增"""
    __tablename__ = 'change_history'
    
    id = Column(Integer, primary_key=True, autoincrement=True)
    project_id = Column(Integer, ForeignKey('projects.id', ondelete='CASCADE'), nullable=False)
    change_type = Column(String(20), nullable=False)
    change_id = Column(String(50), nullable=False)
    change_title = Column(String(255))
    old_status = Column(String(20))
    new_status = Column(String(20))
    old_value = Column(Text)
    new_value = Column(Text)
    change_description = Column(Text)
    changed_at = Column(DateTime, nullable=False)
    synced_at = Column(DateTime, default=datetime.now)
    source = Column(String(50), default='oc_collab')
    
    project = relationship("Project", back_populates="change_history")


# 数据库初始化
from backend.config import config
import os

# 使用绝对路径
db_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'data', 'pm_agent.db')
os.makedirs(os.path.dirname(db_path), exist_ok=True)
db_url = f"sqlite:///{db_path}"

engine = create_engine(db_url, echo=False)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)


def init_db():
    """初始化数据库，创建所有表"""
    Base.metadata.create_all(bind=engine)
    
    # 创建索引（忽略已存在的）
    indexes = [
        ('idx_customers_name', Customer.name),
        ('idx_customers_status', Customer.status),
        ('idx_projects_customer_id', Project.customer_id),
        ('idx_projects_status', Project.status),
        ('idx_projects_confidentiality', Project.confidentiality),
        ('idx_processing_logs_customer_id', ProcessingLog.customer_id),
        ('idx_processing_logs_project_id', ProcessingLog.project_id),
        ('idx_bugs_project_id', Bug.project_id),
        ('idx_bugs_status', Bug.status),
        ('idx_proposals_project_id', Proposal.project_id),
        ('idx_operation_logs_type', OperationLog.operation_type),
        ('idx_materials_project_id', Material.project_id),
        ('idx_materials_file_hash', Material.file_hash),
        ('idx_materials_status', Material.status),
        ('idx_project_templates_project_id', ProjectTemplate.project_id),
        ('idx_project_sync_status_project_id', ProjectSyncStatus.project_id),
        ('idx_project_sync_status_last_sync', ProjectSyncStatus.last_sync_time),
        ('idx_sync_logs_project_id', SyncLog.project_id),
        ('idx_sync_logs_started_at', SyncLog.started_at),
        ('idx_change_history_project_id', ChangeHistory.project_id),
        ('idx_change_history_change_type', ChangeHistory.change_type),
        ('idx_change_history_changed_at', ChangeHistory.changed_at),
    ]
    
    for name, column in indexes:
        try:
            Index(name, column).create(bind=engine)
        except Exception:
            pass  # 忽略已存在的索引


def get_db() -> Generator:
    """获取数据库会话"""
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()
