from sqlalchemy import Column, Integer, String, Text, DateTime, Float, Boolean, BigInteger, ForeignKey, DateTime
from sqlalchemy.dialects.mysql import JSON
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from typing import AsyncGenerator
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from sqlalchemy.orm import sessionmaker, declarative_base
from sqlalchemy.sql import func
from passlib.context import CryptContext
from dotenv import load_dotenv
from sqlalchemy.future import select
from datetime import datetime
import os

# Загружаем переменные окружения
load_dotenv()

# Правильная строка подключения
DATABASE_URL = os.getenv('DATABASE_URL')  # Должно быть "mysql+aiomysql://..." или "postgresql+asyncpg://..."

# Создаём асинхронный движок
# async_engine = create_async_engine(DATABASE_URL, echo=True)
async_engine = create_async_engine(DATABASE_URL, echo=True, pool_recycle=1800, pool_size=10, pool_pre_ping=True )


# Создаём фабрику сессий
async_session = sessionmaker(async_engine, class_=AsyncSession, expire_on_commit=False)

# Базовый класс для моделей
Base = declarative_base()

# Контекст хеширования паролей
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# Функция для инициализации базы данных
async def init_db():
    async with async_engine.begin() as conn:
        await conn.run_sync(Base.metadata.create_all)
    async with async_session() as session:
        # Проверяем, есть ли уже данные в таблице пользователей
        result = await session.execute(select(User).limit(1))
        user_exists = result.scalars().first()

        if not user_exists:
            new_user = User(
                username="admin",
                hashed_password=hash_password("admin123"),  # Пароль хешируем
                role="admin",
                is_active=True
            )
            session.add(new_user)
            await session.commit()

# Зависимость FastAPI для работы с БД
# async def get_async_session() -> AsyncSession:
#     async with async_session() as session:
#         yield session
        
async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
    async with async_session() as session:
        yield session  # Сессия остается открытой во время запроса        


# Функции для хеширования паролей
def hash_password(password: str) -> str:
    return pwd_context.hash(password)

def verify_password(plain_password: str, hashed_password: str) -> bool:
    return pwd_context.verify(plain_password, hashed_password)

# async def get_db():
#     async with SessionLocal() as session:
#         yield session


# Модель пользователя
class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    username = Column(String(55), unique=True, index=True, nullable=False)  # ✅ Правильно
    hashed_password = Column(String(255), nullable=False)
    role = Column(String(55), default="user")
    is_active = Column(Boolean, default=True)
    
    
    applications = relationship("AppliedJob", back_populates="users")

# Модель профиля
class Profile(Base):
    __tablename__ = "profile"

    id = Column(Integer, primary_key=True, index=True)
    link = Column(String(255), unique=True, nullable=True)
    first_name = Column(String(255), nullable=False)
    last_name = Column(String(255), nullable=False)
    pronouns = Column(String(50), nullable=True)
    email = Column(String(255), nullable=True)
    telephone = Column(String(20), nullable=True)
    location = Column(String(255), nullable=True)
    statement = Column(Text, nullable=True)
    skills = Column(JSON, nullable=True)  # JSON-поле для списка навыков
    websites = Column(JSON, nullable=True)  # JSON-поле для списка сайтов
    languages = Column(JSON, nullable=True)  # JSON-поле для языков
    date = Column(DateTime, server_default=func.now())

# Модель вакансий
class Job(Base):
    __tablename__ = "jobs"

    job_id = Column(BigInteger, primary_key=True, index=True)
    job_title = Column(String(255), nullable=False)
    job_company = Column(String(255), nullable=True)
    minimum_annual_salary = Column(Float, nullable=True)
    salary_currency = Column(String(10), nullable=True)
    location_type = Column(String(50), nullable=True)  # Remote, On-site, Hybrid
    location = Column(String(255), nullable=True)
    job_level = Column(String(50), nullable=True)  # Entry-level, Junior, Mid
    job_type = Column(String(50), nullable=True)  # Full-time, Part-time
    days_posted = Column(Integer, nullable=True)
    
    hourly_rate = Column(Float, nullable=True)
    link = Column(String(2083), nullable=True)  # URL вакансии
    link_company = Column(String(2083), nullable=True)  # URL компании
    active = Column(Boolean, default=True)  # Вакансия активна?
    about = Column(Text, nullable=True)
    date_posted = Column(DateTime) 
    data_requested = Column(DateTime, default=datetime.utcnow) 
    
    text = Column(Text, nullable=True)
    
    
    # Связь с AppliedJobs
    applications = relationship("AppliedJob", back_populates="job")



class Client(Base):
    __tablename__ = "client"

    id = Column(Integer, primary_key=True, index=True)
    user_login = Column(String(55), unique=True, index=True, nullable=False)  # ✅ Правильно
    user_nicename = Column(String(55), unique=True, index=True, nullable=True)  # ✅ Правильно
    user_email = Column(String(55), unique=True, index=True, nullable=True)  # ✅ Правильно
    phone = Column(String(55), unique=True, index=True, nullable=True)  # ✅ Правильно
    
    json_data = Column(Text, nullable=True)
    # user_registered = Column(String(2083), nullable=True)  # URL вакансии
    user_status = Column(Boolean, default=True)
    
    # Связь с AppliedJobs (заявки на вакансии)
    applications = relationship("AppliedJob", back_populates="client")
    
class MetaClient(Base):
    __tablename__ = "meta_client"

    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("client.id"), nullable=False)
    meta_key = Column(String(255), nullable=False)
    meta_value = Column(Text, nullable=True)

    # Связь с Client
    client = relationship("Client", back_populates="meta")

# Добавляем обратную связь в Client
Client.meta = relationship("MetaClient", back_populates="client", cascade="all, delete-orphan")

    



class AppliedJob(Base):
    __tablename__ = "applied_jobs"

    id = Column(Integer, primary_key=True, index=True)
    client_id = Column(Integer, ForeignKey("client.id"), nullable=False)
    job_id = Column(BigInteger, ForeignKey("jobs.job_id"), nullable=False)
    applied_on = Column(DateTime, nullable=True)  # ✅ Теперь может быть NULL
    status = Column(String(50), nullable=True)  # ✅ Может быть NULL
    assignee = Column(Integer, ForeignKey("users.id"), nullable=True)  # ✅ Может быть NULL
    priority = Column(String(50), nullable=True)  # ✅ Может быть NULL

    client = relationship("Client", back_populates="applications")
    job = relationship("Job", back_populates="applications")
    users = relationship("User", back_populates="applications")
    
    

    
