from sqlalchemy.orm import Session
from fastapi import HTTPException, status
from typing import Dict, Any
from datetime import timedelta

from app.config import settings
from app.core import create_access_token
from app.repositories import user_repo, order_repo, review_repo
from app.schemas.user_schemas import UserCreate, UserUpdate, AddressCreate, AddressUpdate


# Сервисы аутентификации и пользователей
def register_user(db: Session, user: UserCreate) -> Dict[str, Any]:
    from app.schemas.user_schemas import User as UserSchema
    
    # Создаем пользователя
    db_user = user_repo.create_user(db, user)
    
    # Преобразуем объект SQLAlchemy в схему Pydantic
    user_schema = UserSchema.model_validate(db_user)
    
    # Создаем токен доступа
    access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": db_user.email}, expires_delta=access_token_expires
    )
    
    return {
        "user": user_schema,
        "access_token": access_token,
        "token_type": "bearer"
    }


def login_user(db: Session, email: str, password: str) -> Dict[str, Any]:
    # Аутентифицируем пользователя
    user = user_repo.authenticate_user(db, email, password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Неверный email или пароль",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    # Проверяем, что пользователь активен
    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Неактивный пользователь"
        )
    
    # Создаем токен доступа
    access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.email}, expires_delta=access_token_expires
    )
    
    return {
        "access_token": access_token,
        "token_type": "bearer"
    }


def get_user_profile(db: Session, user_id: int) -> Dict[str, Any]:
    from app.schemas.user_schemas import User as UserSchema, Address as AddressSchema
    from app.schemas.review_schemas import Review as ReviewSchema
    
    user = user_repo.get_user(db, user_id)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="Пользователь не найден"
        )
    
    # Получаем адреса пользователя
    addresses = user_repo.get_user_addresses(db, user_id)
    
    # Получаем заказы пользователя
    orders = order_repo.get_user_orders(db, user_id)
    
    # Получаем отзывы пользователя
    reviews = review_repo.get_user_reviews(db, user_id)
    
    # Преобразуем объекты SQLAlchemy в схемы Pydantic
    user_dict = {
        "id": user.id,
        "email": user.email,
        "phone": user.phone,
        "first_name": user.first_name,
        "last_name": user.last_name,
        "is_active": user.is_active,
        "is_admin": user.is_admin,
        "created_at": user.created_at,
        "updated_at": user.updated_at,
        "addresses": []
    }
    user_schema = UserSchema.model_validate(user_dict)
    addresses_schema = [AddressSchema.model_validate({
        "id": address.id,
        "user_id": address.user_id,
        "address_line1": address.address_line1,
        "address_line2": address.address_line2,
        "city": address.city,
        "state": address.state,
        "postal_code": address.postal_code,
        "country": address.country,
        "is_default": address.is_default,
        "created_at": address.created_at,
        "updated_at": address.updated_at
    }) for address in addresses]
    reviews_schema = [ReviewSchema.model_validate(review.__dict__) for review in reviews]
    
    return {
        "user": user_schema,
        "addresses": addresses_schema,
        "orders": orders,  # Заказы обрабатываются отдельно в сервисе заказов
        "reviews": reviews_schema
    }


def update_user_profile(db: Session, user_id: int, user_data: UserUpdate) -> Dict[str, Any]:
    from app.schemas.user_schemas import User as UserSchema
    
    updated_user = user_repo.update_user(db, user_id, user_data)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    user_schema = UserSchema.model_validate(updated_user)
    return {"user": user_schema}


def add_user_address(db: Session, user_id: int, address: AddressCreate) -> Dict[str, Any]:
    from app.schemas.user_schemas import Address as AddressSchema
    
    new_address = user_repo.create_address(db, address, user_id)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    address_schema = AddressSchema.model_validate(new_address)
    return {"address": address_schema}


def update_user_address(db: Session, user_id: int, address_id: int, address: AddressUpdate) -> Dict[str, Any]:
    from app.schemas.user_schemas import Address as AddressSchema
    
    updated_address = user_repo.update_address(db, address_id, address, user_id)
    # Преобразуем объект SQLAlchemy в схему Pydantic
    address_schema = AddressSchema.model_validate(updated_address)
    return {"address": address_schema}


def delete_user_address(db: Session, user_id: int, address_id: int) -> Dict[str, Any]:
    success = user_repo.delete_address(db, address_id, user_id)
    return {"success": success}


def request_password_reset(db: Session, email: str) -> Dict[str, Any]:
    """Запрос на сброс пароля"""
    # Проверяем, существует ли пользователь с таким email
    user = user_repo.get_user_by_email(db, email)
    if not user:
        # Не сообщаем, что пользователь не существует (безопасность)
        return {"message": "Если указанный email зарегистрирован, на него будет отправлена инструкция по сбросу пароля"}
    
    # Генерируем токен для сброса пароля
    reset_token = user_repo.create_password_reset_token(db, user.id)
    
    # В реальном приложении здесь должна быть отправка email
    # Для примера просто возвращаем токен
    return {
        "message": "Инструкция по сбросу пароля отправлена на указанный email",
        "token": reset_token  # В реальном приложении не возвращаем токен
    }


def reset_password(db: Session, token: str, new_password: str) -> Dict[str, Any]:
    """Сброс пароля по токену"""
    # Проверяем токен и получаем пользователя
    user_id = user_repo.verify_password_reset_token(db, token)
    if not user_id:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Недействительный или устаревший токен сброса пароля"
        )
    
    # Обновляем пароль
    user_repo.update_password(db, user_id, new_password)
    
    return {"message": "Пароль успешно изменен"}


def change_password(db: Session, user_id: int, current_password: str, new_password: str) -> Dict[str, Any]:
    """Изменение пароля авторизованным пользователем"""
    # Проверяем текущий пароль
    user = user_repo.get_user(db, user_id)
    if not user or not user_repo.verify_password(current_password, user.password):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Неверный текущий пароль"
        )
    
    # Обновляем пароль
    user_repo.update_password(db, user_id, new_password)
    
    return {"message": "Пароль успешно изменен"} 