import json
import ast
import requests

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from sqlalchemy.orm import joinedload
from sqlalchemy import delete
from sqlalchemy import update
from sqlalchemy import or_
from sqlalchemy import select, and_
from sqlalchemy.exc import IntegrityError
from model.database import Client, AppliedJob, Job

from dotenv import load_dotenv
import os

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


url_up = os.getenv('UP_DOMEN')




async def get_filtered_jobs(db: AsyncSession, user_job_titles, minimum_annual_salary, salary_currency,
                            user_location_type, user_locations, user_levels, user_job_types): #
    # Строим фильтры для каждого из параметров пользователя
    filters = []

    # Фильтрация по job_title (примерное совпадение)
    if user_job_titles:
        title_filters = [Job.job_title.ilike(f"%{title}%") for title in user_job_titles]
        filters.append(or_(*title_filters))

    # Фильтрация по minimum_annual_salary (если указано)
    if minimum_annual_salary is not None:
        filters.append(Job.minimum_annual_salary >= minimum_annual_salary)

    # Фильтрация по salary_currency (если указано)
    if salary_currency is not None:
        filters.append(Job.salary_currency == salary_currency)

    # Фильтрация по location_type (если указано)
    if user_location_type:
        filters.append(Job.location_type == user_location_type)

    # Фильтрация по location (разделяем по каждому городу)
    if user_locations:
        location_filters = [Job.location.ilike(location) for location in user_locations]
        filters.append(or_(*location_filters))

    # Фильтрация по job_level (если указаны)
    if user_levels:
        filters.append(Job.job_level.in_(user_levels))

    # Фильтрация по job_type (если указаны)
    if user_job_types:
        filters.append(Job.job_type.in_(user_job_types))

    # Выполняем запрос с применением всех фильтров
    query = select(Job).filter(*filters)

    # Выполняем асинхронный запрос
    result = await db.execute(query)

    # Получаем все результаты
    jobs = result.scalars().all()

    return jobs

async def upsert_client(db: AsyncSession, user_id: str, user_login: str,  user_nicename: str, user_email: str, phone: str, json_data: str):
    # Проверяем, существует ли клиент с таким логином или email
    async with db.begin():
        result = await db.execute(
            select(Client).filter((Client.id == user_id))# | (Client.user_email == user_email))
        )
        client = result.scalars().first()  # Получаем первый результат или None

    if client:
        # Если клиент существует, обновляем его данные
        client.user_nicename = user_login
        client.phone = phone
        client.json_data = json_data
        # Можно добавить другие поля для обновления

        try:
            await db.commit()  # Применяем изменения в базе данных
            await db.refresh(client)  # Обновляем объект в Python
            return client
        except IntegrityError:
            await db.rollback()  # В случае ошибки откатываем изменения
            raise
    else:
        # Если клиента нет, создаем нового
        new_client = Client(
            user_login=user_login,
            user_nicename=user_nicename,
            user_email=user_email,
            json_data=json_data,
        )
        db.add(new_client)
        try:
            await db.commit()  # Сохраняем нового клиента в базе данных
            await db.refresh(new_client)  # Обновляем объект в Python
            return new_client
        except IntegrityError:
            await db.rollback()  # В случае ошибки откатываем изменения
            raise
        
        
        
        
async def del_jobs(db: AsyncSession, user_id: str):
    jobs = await db.execute(
        select(AppliedJob).where(
            AppliedJob.client_id == user_id,
            or_(
            AppliedJob.status.in_(["Scheduled", "Backlogged"]),
            AppliedJob.status.is_(None)
        )
        )
    )
    jobs = jobs.scalars().all()

    for job in jobs:
        await db.delete(job)
    
    await db.commit()
    
    
# async def add_jobs(db: AsyncSession, user_id: str):
#      # Фильтруем вакансии по переданным параметрам
#     query = select(Job).filter(Job.active == 3)
#     result = await db.execute(query)
#     jobs = result.scalars().all()  # Получаем список вакансий

#     if not jobs:
#         return {"message": "Нет вакансий по данному фильтру"}

#     # Создаём записи в AppliedJob
#     applied_jobs = [
#         AppliedJob(client_id=user_id, job_id=job.job_id, status="Scheduled")
#         for job in jobs
#     ]

#     db.add_all(applied_jobs)  # Добавляем в сессию
#     await db.commit()  # Фиксируем изменения
    
    

#     return {"message": f"{len(applied_jobs)} вакансий добавлено в AppliedJob"}
    

async def add_jobs(db: AsyncSession, user_id: str):
    # Получаем все активные вакансии (предполагаю, что ты хотел использовать True, а не 3)
    query = select(Job).where(Job.active == 3)
    result = await db.execute(query)
    jobs = result.scalars().all()

    if not jobs:
        return {"message": "Нет вакансий по данному фильтру"}

    applied_jobs = []
    scheduled_count = 0

    for job in jobs:
        # Проверяем, существует ли уже такая пара client_id + job_id
        check_query = select(AppliedJob).where(
            and_(
                AppliedJob.client_id == user_id,
                AppliedJob.job_id == job.job_id
            )
        )
        check_result = await db.execute(check_query)
        existing = check_result.scalar_one_or_none()

        if not existing:
            # Первые 5 добавим со статусом Scheduled, остальные Backlogged
            status = "Scheduled" if scheduled_count < 5 else "Backlogged"
            applied_jobs.append(
                AppliedJob(client_id=user_id, job_id=job.job_id, status=status)
            )
            if status == "Scheduled":
                scheduled_count += 1

    if applied_jobs:
        db.add_all(applied_jobs)
        await db.commit()
        return {"message": f"{len(applied_jobs)} вакансий добавлено в AppliedJob (Scheduled: {scheduled_count})"}
    else:
        return {"message": "Все вакансии уже были добавлены ранее"}
    
    
async def get_applied_jobs(db, client_id: int):
    query = (
        select(AppliedJob)
        .options(joinedload(AppliedJob.job))  # Подгружаем данные о вакансии
        .where(AppliedJob.client_id == client_id)
    )
    
    result = await db.execute(query)
    applied_jobs = result.scalars().all()

    if not applied_jobs:
        return {"message": "Нет откликов на вакансии"}

    jobs_list = []
    
    for applied in applied_jobs:
        job = applied.job  # Получаем объект Job из отношения AppliedJob.job
        
        jobs_list.append({
            "id": job.job_id,
            "title": job.job_title,
            "company": job.job_company,
            "postedDate": job.date_posted,
            "AppliedDate": applied.applied_on,
            "location": job.location,
            "jobType": job.job_type,
            "salary": f"${job.minimum_annual_salary}K" if job.minimum_annual_salary else "Not specified",
            "level": job.job_level,
            "status": applied.status if applied.status else "Scheduled",
            "requiredSkills": "",
            "aboutJob": job.about,
            "jobLink": job.link
        })
    print(jobs_list)
    return jobs_list



async def client_list(client_id: int, db):
    result = await db.execute(
        select(Client).filter((Client.id == client_id))# | (Client.user_email == user_email))
    )
    clients = result.scalars().first()
    clients_str= clients.json_data
   # Если клиент найден
    if clients:
        client_dict = ast.literal_eval(clients_str)
        # result = {client_id: client_dict}
        print(f"===============================!!!!!{type(client_dict)}")
       
        return client_dict
    else:
        # Если клиент не найден, возвращаем None или обрабатываем ошибку
        # return None
        print("NOTTTTTTTTTTTTTTTTTTTTTTTTTTTTT")
        
        
        
async def get_avtopilot(db, data):
    try:
        client_id = data.user_id  # Используем client_id вместо user_id для согласованности
        avtopilotss = data.avtopilot
        
        if avtopilotss is True:
            # Для асинхронного обновления используем update().where().values()
            stmt = (
                update(AppliedJob)
                .where(
                    (AppliedJob.client_id == client_id) & 
                    (AppliedJob.status == "Paused")
                )
                .values(status="Scheduled")
            )
            await db.execute(stmt)
            await db.commit()
            return True
            
        elif avtopilotss is False:
            stmt = (
                update(AppliedJob)
                .where(
                    (AppliedJob.client_id == client_id) & 
                    (AppliedJob.status == "Scheduled")
                )
                .values(status="Paused")
            )
            await db.execute(stmt)
            await db.commit()
            return True
            
        else:
            print("error")
            return False
            
    except Exception as e:
        print(f"Ошибка при обработке данных: {e}")
        await db.rollback()
        raise HTTPException(status_code=400, detail="Error processing data")
    
    
async def get_delite(db, data):
    try:
        client_id = data.user_id  # Обратите внимание на точку вместо квадратных скобок
        job_id = data.job_id    # Так как data - это объект Pydantic модели
        
        print(f"Полученные данные: user_id={client_id}, avtopilotss={job_id}")
        stmt = delete(AppliedJob).where(
            (AppliedJob.client_id == client_id) & 
            (AppliedJob.job_id == job_id)
        )
        
        # Выполняем запрос с await
        result = await db.execute(stmt)
        await db.commit()
        
        # Получаем количество удаленных строк
        deleted_count = result.rowcount
        print(f"Удалено записей: {deleted_count}")
            
        
    except Exception as e:
        print(f"Ошибка при обработке данных: {e}")
        raise HTTPException(status_code=400, detail="Error processing data")
    
    
    


async def get_update(db: AsyncSession, data: update):
    user_id = data.user_id
    up_client = requests.get(f"{url_up}{user_id}")  # Лучше заменить на httpx.AsyncClient
    
    if up_client.status_code == 200:
        datas = up_client.json()
        
        # Проверяем, что 'json_data' есть в ответе
        if 'json_data' not in datas:
            raise HTTPException(status_code=400, detail="Missing 'json_data' in response")
        
        json_data = datas['json_data']
        
        # Если json_data — строка, парсим её в словарь
        if isinstance(json_data, str):
            try:
                data_dict = json.loads(json_data)
            except json.JSONDecodeError:
                raise HTTPException(status_code=400, detail="Invalid JSON in 'json_data'")
        else:
            data_dict = json_data  # Если уже словарь, используем как есть
        
        # Проверяем, что data_dict — словарь
        if not isinstance(data_dict, dict):
            raise HTTPException(status_code=400, detail="'json_data' is not a valid dictionary")
        
        try:
            first_name = data_dict['first_name']
            last_name = data_dict['last_name']
            email_addr = data_dict['email_addr']
            user_id = data_dict['user_id']
            phone_num = data_dict['phone_num']
            print(data_dict)
            
            # Обновляем или создаём клиента
            async with db.begin():
                client = await db.get(Client, user_id)  # Ищем клиента по ID
                
                if client:
                    # Обновляем существующего клиента
                    client.user_nicename = first_name  # Исправлено: было user_login
                    client.phone = phone_num
                    client.json_data = str(data_dict)
                else:
                    # Создаём нового клиента
                    client = Client(
                        id=user_id,
                        user_login=email_addr,  # Или другой логин
                        user_nicename=f"{first_name} {last_name}",
                        user_email=email_addr,
                        phone=phone_num,
                        json_data=str(data_dict),
                    )
                    db.add(client)
                    
                
                await db.commit()
                return client
                
        except KeyError as e:
            raise HTTPException(status_code=400, detail=f"Missing required field: {e}")
    else:
        raise HTTPException(status_code=up_client.status_code, detail="Failed to fetch data")
    
    

