from datetime import datetime
from dateutil import parser
from typing import Optional, List, Dict, Any
from pymongo.errors import DuplicateKeyError
from fastapi import HTTPException, Depends
from app.db import database
from app.v1.integrations.SMTPmailer import send_email
from bson import ObjectId  # Import ObjectId for converting string to MongoDB ObjectId
from app.v1.libraries.object import str_to_objectid
from app.v1.models.saas.accountmodel import AccountCreate, AccountUpdate, Account, Accounts
from app.v1.models.saas.usersmodel import User
from app.v1.services.sequence import get_next_sequence_value, convert_enums

COLLECTION_NAME = "accounts"
USER_COLLECTION_NAME = "users"

def create_account_service(account: AccountCreate, db: database.MongoDB) -> dict:
    account_data = account.dict()
    account_data["created_date"] = datetime.utcnow()

    # Convert Enums explicitly to strings for MongoDB
    account_data["purposes_of_use"] = [purpose.value for purpose in account_data.get("purposes_of_use", [])]
    account_data["fleet_capabilities"] = [capability.value for capability in account_data.get("fleet_capabilities", [])]
    account_data["workforce_capabilities"] = [capability.value for capability in account_data.get("workforce_capabilities", [])]
    account_data["industry"] = account_data["industry"].value if account_data.get("industry") else None
    account_data["subscription_status"] = account_data["subscription_status"].value if account_data.get("subscription_status") else None
    account_data["workforce_count"] = account_data["workforce_count"].value
    account_data["revenues"] = account_data["revenues"].value

    accounts_collection = db[COLLECTION_NAME]
    account_data["accounts_id"] = get_next_sequence_value("accounts_id", db)

    try:
        result = accounts_collection.insert_one(account_data)
    except DuplicateKeyError as e:
        if "email" in str(e):
            raise ValueError("Account with this email already exists.")
        elif "mobile" in str(e):
            raise ValueError("Account with this mobile number already exists.")
        else:
            raise ValueError("Duplicate key error.")
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Database error: {str(e)}")

    # Set account_id in the account data
    account_data["_id"] = str(result.inserted_id)
    account_data["account_id"] = account_data["_id"]

    # Update the user's record with the new account_id. Convert user_id to ObjectId.
    users_collection = db["users"]
    try:
        update_result = users_collection.update_one(
            {"_id": ObjectId(account_data["user_id"])},
            {"$set": {"account_id": account_data["account_id"]}}
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Failed to update user: {str(e)}")

    if update_result.modified_count == 0:
        # No user record was updated—this might indicate that no user with that _id exists.
        raise HTTPException(status_code=500, detail="Failed to update user with account_id.")

    # Send a welcome email
    subject = "Your Organization has been created!"
    body = f"Hello {account.name},\n\nThank you for signing up for our platform. We're excited to have you on board!"
    send_email(subject, body, account.email)

    return account_data

def get_accounts_service(
    skip: int, 
    limit: int, 
    q: Optional[str], 
    account_type: Optional[str], 
    is_active: Optional[bool],
    subscription_status: Optional[str],
    reg_date_from: Optional[str],
    reg_date_to: Optional[str],
    workforce_count_range: Optional[str],
    fleet_count_range: Optional[str],
    revenue_range: Optional[str],
    account_id: Optional[str],
    db,
    current_user
) -> Dict[str, Any]:
    
    # Convert reg_date_from and reg_date_to to datetime if provided.
    dt_from = None
    dt_to = None
    if reg_date_from and reg_date_from.strip():
        try:
            dt_from = parser.parse(reg_date_from)
        except Exception:
            raise ValueError(f"Invalid reg_date_from: {reg_date_from}")
    if reg_date_to and reg_date_to.strip():
        try:
            dt_to = parser.parse(reg_date_to)
        except Exception:
            raise ValueError(f"Invalid reg_date_to: {reg_date_to}")
    
    # Only roles 1 or 2 are allowed to view accounts.
    if current_user.get("roles", 0) not in [1, 2]:
        raise ValueError("Not permitted to view accounts.")
    
    collection = db["accounts"]
    query = {}
    
    # Text search across a few fields.
    if q:
        regex_query = {"$regex": q, "$options": "i"}
        query["$or"] = [
            {"account_name": regex_query},
            {"name": regex_query},
            {"country": regex_query},
            {"city": regex_query}
        ]
    
    # Additional filters.
    if account_type:
        query["account_type"] = account_type
    if is_active is not None:
        query["is_active"] = is_active
    if subscription_status:
        query["subscription_status"] = subscription_status
    if dt_from or dt_to:
        date_query = {}
        if dt_from:
            date_query["$gte"] = dt_from
        if dt_to:
            date_query["$lte"] = dt_to
        query["created_date"] = date_query
    
    # Use the provided search values directly,
    # assuming the frontend sends exact enum string values.
    if workforce_count_range:
        query["workforce_count"] = workforce_count_range
    if fleet_count_range:
        query["fleet_count"] = fleet_count_range
    if revenue_range:
        query["revenues"] = revenue_range

    accounts_cursor = collection.find(query).skip(skip).limit(limit)
    accounts_list = []
    for account in accounts_cursor:
        account["id"] = str(account["_id"])
        account["account_id"] = str(account["_id"])
        if "created_date" in account and isinstance(account["created_date"], datetime):
            account["created_date"] = account["created_date"].isoformat()
        accounts_list.append(account)
    
    total_count = collection.count_documents(query)
    return {"total_count": total_count, "accounts": accounts_list}


def get_account_service(account_id: str, db: database.MongoDB) -> dict:
    collection = db[COLLECTION_NAME]
    account = collection.find_one({"_id": str_to_objectid(account_id)})
    if account:
        account["_id"] = str(account["_id"])
        account["account_id"] = account["_id"]

    print(f"Account: {account}")
    return account

def update_account_service(
    account_id: str, 
    account_update: AccountUpdate, 
    current_user: dict, 
    db: database.MongoDB
) -> dict:
    accounts_collection = db[COLLECTION_NAME]
    users_collection = db[USER_COLLECTION_NAME]

    
    existing_account = accounts_collection.find_one({"_id": str_to_objectid(account_id)})
    if not existing_account:
        raise ValueError("Account not found")

    
    user_document = users_collection.find_one({"_id": str_to_objectid(current_user.get("_id"))})
    if not user_document:
        raise ValueError("User not found")
    
    # Check if the current user is authorized to update the account
    if current_user.get("roles") != 1:
        if str(user_document.get("account_id")) != account_id:
            print("account id mismach")
            raise ValueError("Not authorized to update this account")
        

    account_updates = account_update.dict(exclude={"user_id", "account_type"})

    account_updates = convert_enums(account_updates)

    #account_updates.pop("roles", None)  # Remove roles field if present
    
    # For example, only users with role 3 may update the account
    if current_user.get("roles") == 100 or current_user.get("roles") == 1 :  #Role 3== Account Admin
        accounts_collection.update_one({"_id": str_to_objectid(account_id)}, {"$set": account_updates})
    

    # Optionally update user data in the users collection
    #user_update_data = {"name": account_update.name, "mobile": account_update.mobile}
    #users_collection.update_one({"_id": current_user["_id"]}, {"$set": user_update_data})
    
    updated_account = accounts_collection.find_one({"_id": str_to_objectid(account_id)})
    if updated_account:
        updated_account["_id"] = str(updated_account["_id"])
        updated_account["account_id"] = updated_account["_id"]
        return updated_account
    else:
        raise ValueError("Account not found after update")

def delete_account_service(account_id: str, db: database.MongoDB) -> dict:
    collection = db[COLLECTION_NAME]
    account = collection.find_one({"_id": str_to_objectid(account_id)})
    if not account:
        raise ValueError("Account not found")
    collection.delete_one({"_id": str_to_objectid(account_id)})
    account["_id"] = str(account["_id"])
    account["account_id"] = account["_id"]
    return account
