from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from fastapi import HTTPException
from datetime import datetime
from src.apps.stores.models import Store, Branch, StoreType
from src.apps.stores.schemas import StoreCreate, StoreResponse, BranchCreate, BranchResponse
from src.apps.auth.controller import get_current_user
from src.apps.users.models import User  # Adjust the import path based on your actual project structure



# ---------------- Store Services ----------------

def get_store_by_user(db: Session, current_user: User):
    """
    Check if a user already has a store.
    """
    return db.query(Store).filter(Store.user_id == current_user.user_id).first()


def get_store_by_id(db: Session,current_user: User):
    """
    Check if a store exists by store_id.
    """
    return db.query(Store).filter(Store.user_id == current_user.user_id).first()


def get_store_by_name(db: Session, store_name: str):
    """
    Get a store by its name.
    """
    return db.query(Store).filter(Store.name == store_name).first()

def create_store(db: Session, store: StoreCreate, current_user: User):
    # Ensure the provided storetype_id exists in store_type table
    store_type = db.query(StoreType).filter(StoreType.storetype_id == store.storetype_id).first()
    if not store_type:
        raise HTTPException(
            status_code=400,
            detail={"status": False, "code": 400, "message": "Invalid store type selected."}
        )

    # Create the store with branch_limit = 2
    new_store = Store(
        user_id=current_user.user_id,
        storetype_id=store.storetype_id,  # ✅ Add storetype_id
        name=store.name,
        branch_limit=2  # ✅ Set branch limit to 2 by default
    )
    db.add(new_store)
    db.commit()
    db.refresh(new_store)

    # Extract the first branch details
    first_branch = store.branches[0]  # Always at least one branch

    # Create the first branch along with the store
    new_branch = Branch(
        store_id=new_store.store_id,
        user_id=current_user.user_id,
        branch_name=first_branch.branch_name,
        address=first_branch.address,
        contact_info=first_branch.contact_info
    )
    db.add(new_branch)
    db.commit()
    db.refresh(new_branch)

    return {
        "store_id": new_store.store_id,
        "name": new_store.name,
        "storetype_id": new_store.storetype_id,  # Include storetype_id in response
        "branch_limit": new_store.branch_limit,
        "user_id": current_user.user_id,
        "created_at": new_store.created_at.isoformat(),
        "updated_at": new_store.updated_at.isoformat(),
        "branches": [
            {
                "branch_id": new_branch.branch_id,
                "store_id": new_branch.store_id,
                "branch_name": new_branch.branch_name,
                "address": new_branch.address,
                "contact_info": new_branch.contact_info,
                "user_id": current_user.user_id,
                "created_at": new_branch.created_at.isoformat(),
                "updated_at": new_branch.updated_at.isoformat(),
            }
        ]
    }



def update_store_name(db: Session, new_store_name: str, current_user: User) -> dict:
    """
    Update the store's name and updated_at timestamp based on the current user.
    Ensures store name uniqueness before updating.
    """
    # Fetch the current store of the user
    store = get_store_by_user(db, current_user)
    if not store:
        raise HTTPException(
            status_code=404,
            detail={"status": False, "code": 404, "message": "Store not found"}
        )
    
    # Ensure new name is unique (excluding the current store)
    if db.query(Store).filter(Store.name == new_store_name, Store.store_id != store.store_id).first():
        raise HTTPException(
            status_code=400,
            detail={"status": False, "code": 400, "message": "Store name must be unique."}
        )

    # Update the store name and timestamp
    store.name = new_store_name
    store.updated_at = datetime.utcnow()

    try:
        db.commit()  # Save changes
        db.refresh(store)  # Refresh to return updated store
    except IntegrityError:
        db.rollback()  # Revert changes on failure
        raise HTTPException(
            status_code=400,
            detail={"status": False, "code": 400, "message": "Failed to update store name due to database constraint."}
        )

    # Fetch branches related to the store
    branches = db.query(Branch).filter(Branch.store_id == store.store_id).all()
    
    # Format branch data
    branch_list = [
        {
            "branch_id": branch.branch_id,
            "store_id": branch.store_id,
            "branch_name": branch.branch_name,
            "address": branch.address,
            "contact_info": branch.contact_info,
            "created_at": branch.created_at,
            "updated_at": branch.updated_at
        } for branch in branches
    ]

    return {
        "status": True,
        "code": 200,
        "message": "Store name updated successfully",
        "data": [
            {
                "store_id": store.store_id,
                "name": store.name,
                "user_id": store.user_id,
                "created_at": store.created_at,
                "updated_at": store.updated_at,
                "branches": branch_list  # Include branches
            }
        ]
    }


def delete_store(db: Session, current_user: User):
    """
    Delete a store and all its associated branches.
    The store ID is automatically retrieved based on the authenticated user.
    """

    # Ensure current_user is a User object
    if not isinstance(current_user, User):
        raise HTTPException(status_code=400, detail={"status": False, "code": 400, "message":"Invalid user object"})
    

    store = db.query(Store).filter(Store.user_id == current_user.user_id).first()
    if not store:
        raise HTTPException(status_code=404, detail={"status": False, "code": 404, "message":"Store not found or unauthorized"})

    try:
        # Delete all associated branches first
        db.query(Branch).filter(Branch.store_id == store.store_id).delete()
        # Delete store
        db.delete(store)
        db.commit()
        return {"status": True, 
                "code": 200,
                "message": "Store and all associated branches deleted successfully"}

    except Exception as e:
        raise HTTPException(status_code=500, detail={"status": False, "code": 500, "message": f"An error occurred while deleting the store: {str(e)}"})
         


# ---------------- Branch Services ----------------

def get_branch_by_id(db: Session, store_id: str, branch_id: str, current_user: User):
    """
    Retrieve a branch using store_id and branch_id. Ensures the branch belongs to the current user's store.
    """
    store = db.query(Store).filter(Store.store_id == store_id, Store.user_id == current_user.user_id).first()
    if not store:
        raise HTTPException(status_code=404, detail="Store not found or unauthorized.")

    branch = db.query(Branch).filter(Branch.store_id == store_id, Branch.branch_id == branch_id).first()
    if not branch:
        raise HTTPException(status_code=404, detail="Branch not found.")

    return branch


def create_branch(db: Session, branch: BranchCreate, current_user: User) -> dict:
    """
    Create a new branch for the authenticated user using store_id.
    """
    # Check if the user owns a store
    store = db.query(Store).filter(Store.user_id == current_user.user_id).first()
    if not store:
        raise HTTPException(
            status_code=404, 
            detail={"status": False, "code": 404, "message": "Store not found."}
        )

    # Ensure branch name is unique within the store
    existing_branch = db.query(Branch).filter(
        Branch.store_id == store.store_id,
        Branch.branch_name == branch.branch_name
    ).first()
    if existing_branch:
        raise HTTPException(
            status_code=400, 
            detail={"status": False, "code": 400, "message": "Branch name must be unique within the store."}
        )

    # Create new branch
    new_branch = Branch(
        store_id=store.store_id,
        branch_name=branch.branch_name,
        address=branch.address,
        contact_info=branch.contact_info,
        user_id=current_user.user_id,
        created_at=datetime.utcnow(),
        updated_at=datetime.utcnow()
    )

    try:
        db.add(new_branch)
        db.commit()
        db.refresh(new_branch)
    except Exception:
        db.rollback()
        raise HTTPException(
            status_code=500, 
            detail={"status": False, "code": 500, "message": "An error occurred while creating the branch."}
        )

    return {
        "status": True,
        "code": 200,
        "message": "Branch created successfully",
        "data": [
            {
                "branch_id": new_branch.branch_id,
                "store_id": new_branch.store_id,
                "branch_name": new_branch.branch_name,
                "address": new_branch.address,
                "contact_info": new_branch.contact_info,
                "created_at": new_branch.created_at,
                "updated_at": new_branch.updated_at,
                "user_id": new_branch.user_id,
            }
        ]
    }

def get_branches_by_store_id(db: Session, store_id: str, current_user: User):
    """
    Retrieve all branches of a given store_id if the store belongs to the authenticated user.
    """
    store = db.query(Store).filter(
        Store.store_id == store_id, 
        Store.user_id == current_user.user_id  # ✅ Ensures store belongs to the user
    ).first()

    if not store:
        raise HTTPException(status_code=404, detail="Store not found or does not belong to the user.")

    branches = db.query(Branch).filter(Branch.store_id == store_id).all()

    if not branches:
        raise HTTPException(status_code=404, detail="No branches found for this store.")

    return [
        BranchResponse(
            branch_id=branch.branch_id,
            store_id=branch.store_id,
            branch_name=branch.branch_name,
            address=branch.address,
            contact_info=branch.contact_info,
            created_at=branch.created_at,
            updated_at=branch.updated_at,
            user_id=branch.user_id,
        ) 
        for branch in branches
    ]


def update_branch(db: Session, branch_id: str, branch: BranchCreate, current_user: User) -> dict:
    """
    Update a branch using branch_id. Ensures the branch belongs to the authenticated user.
    """
    store = db.query(Store).filter(Store.user_id == current_user.user_id).first()
    if not store:
        raise HTTPException(
            status_code=404,
            detail={"status": False, "code": 404, "message": "Store not found."}
        )

    branch_to_update = db.query(Branch).filter(Branch.store_id == store.store_id, Branch.branch_id == branch_id).first()
    if not branch_to_update:
        raise HTTPException(
            status_code=404,
            detail={"status": False, "code": 404, "message": "Branch not found."}
        )

    existing_branch = db.query(Branch).filter(Branch.store_id == store.store_id, Branch.branch_name == branch.branch_name).first()
    if existing_branch and existing_branch.branch_id != branch_to_update.branch_id:
        raise HTTPException(
            status_code=400,
            detail={"status": False, "code": 400, "message": "Branch name must be unique within the store."}
        )

    # Update branch details
    branch_to_update.branch_name = branch.branch_name
    branch_to_update.address = branch.address
    branch_to_update.contact_info = branch.contact_info
    branch_to_update.updated_at = datetime.utcnow()

    try:
        db.commit()
        db.refresh(branch_to_update)
    except Exception:
        db.rollback()
        raise HTTPException(
            status_code=500,
            detail={"status": False, "code": 500, "message": "An error occurred while updating the branch."}
        )

    return {
        "status": True,
        "code": 200,
        "message": "Branch updated successfully",
        "data": [
            {
                "branch_id": branch_to_update.branch_id,
                "store_id": branch_to_update.store_id,
                "branch_name": branch_to_update.branch_name,
                "address": branch_to_update.address,
                "contact_info": branch_to_update.contact_info,
                "created_at": branch_to_update.created_at,
                "updated_at": branch_to_update.updated_at,
                "user_id": branch_to_update.user_id,
            }
        ]
    }


def delete_branch(db: Session, branch_id: str, current_user: User):
    """
    Delete a branch using branch_id. Ensures the branch belongs to the authenticated user.
    """
    store = db.query(Store).filter(Store.user_id == current_user.user_id).first()
    if not store:
        raise HTTPException(status_code=404, detail={"status": False, "code": 404, "message":"Store not found."})

    branch_to_delete = db.query(Branch).filter(Branch.store_id == store.store_id, Branch.branch_id == branch_id).first()
    if not branch_to_delete:
        raise HTTPException(status_code=404, detail={"status": False, "code": 404, "message":"Branch not found."})

    try:
        db.delete(branch_to_delete)
        db.commit()
    except Exception:
        db.rollback()
        raise HTTPException(status_code=500, detail={"status": False, "code": 500, "message":"An error occurred while deleting the branch."})

    return {"status": True,
        "code": 200,
        "message": "Branch deleted successfully."}