"""
User and Role Seeder
Creates default roles and an admin user
"""
import sys
from pathlib import Path
from datetime import datetime, timezone
import bcrypt

# Add parent directory to path to import modules
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))

from sqlalchemy.orm import Session
from src.shared.config.database import SessionLocal
# Import all models to ensure relationships are properly initialized
from src.models import *
from src.auth.models.role import Role
from src.auth.models.user import User
from src.shared.config.logging_config import get_logger

logger = get_logger(__name__)


def get_roles_data():
    """Generate default roles data"""
    return [
        {
            'name': 'admin',
            'description': 'Full system access with all administrative privileges'
        },
        {
            'name': 'staff',
            'description': 'Hotel staff with operational access'
        },
        {
            'name': 'customer',
            'description': 'Regular customer/guest user'
        },
        {
            'name': 'accountant',
            'description': 'Financial management and accounting access'
        },
  
        {
            'name': 'housekeeping',
            'description': 'Housekeeping and room management access'
        }
    ]


def seed_roles(db: Session):
    """Seed roles into the database"""
    try:
        roles_data = get_roles_data()
        created_count = 0
        updated_count = 0
        role_map = {}
        
        for role_data in roles_data:
            existing = db.query(Role).filter(Role.name == role_data['name']).first()
            
            if existing:
                logger.info(f'Role already exists: {role_data["name"]}')
                role_map[role_data['name']] = existing
            else:
                logger.info(f'Creating role: {role_data["name"]}')
                role = Role(**role_data)
                db.add(role)
                db.flush()  # Flush to get the ID
                role_map[role_data['name']] = role
                created_count += 1
        
        db.commit()
        logger.info(f'Role seeding completed! Created: {created_count}, Existing: {len(roles_data) - created_count}')
        return role_map
        
    except Exception as e:
        logger.error(f'Error seeding roles: {str(e)}', exc_info=True)
        db.rollback()
        raise


def seed_admin_user(db: Session, admin_role: Role, email: str = 'admin@hotel.com', password: str = 'admin123', full_name: str = 'Admin User'):
    """Seed admin user into the database"""
    try:
        # Check if admin user already exists
        existing = db.query(User).filter(User.email == email).first()
        
        if existing:
            logger.info(f'Admin user already exists: {email}')
            # Update role if needed
            if existing.role_id != admin_role.id:
                existing.role_id = admin_role.id
                existing.updated_at = datetime.now(timezone.utc)
                db.commit()
                logger.info(f'Updated admin user role: {email}')
            return existing
        
        # Create new admin user
        logger.info(f'Creating admin user: {email}')
        password_bytes = password.encode('utf-8')
        salt = bcrypt.gensalt()
        hashed_password = bcrypt.hashpw(password_bytes, salt).decode('utf-8')
        
        admin_user = User(
            email=email,
            password=hashed_password,
            full_name=full_name,
            role_id=admin_role.id,
            is_active=True,
            phone=None,
            address=None
        )
        
        db.add(admin_user)
        db.commit()
        db.refresh(admin_user)
        logger.info(f'Admin user created successfully: {email}')
        return admin_user
        
    except Exception as e:
        logger.error(f'Error seeding admin user: {str(e)}', exc_info=True)
        db.rollback()
        raise


def seed_users_and_roles(db: Session, admin_email: str = 'admin@hotel.com', admin_password: str = 'admin123', admin_name: str = 'Admin User'):
    """Seed roles and admin user"""
    try:
        # First, seed roles
        role_map = seed_roles(db)
        
        # Get admin role
        admin_role = role_map.get('admin')
        if not admin_role:
            raise ValueError('Admin role not found after seeding')
        
        # Seed admin user
        admin_user = seed_admin_user(db, admin_role, admin_email, admin_password, admin_name)
        
        return role_map, admin_user
        
    except Exception as e:
        logger.error(f'Error seeding users and roles: {str(e)}', exc_info=True)
        raise


def main():
    """Main function to run the seeder"""
    import argparse
    
    parser = argparse.ArgumentParser(description='Seed roles and admin user')
    parser.add_argument(
        '--email',
        default='admin@hotel.com',
        help='Admin user email (default: admin@hotel.com)'
    )
    parser.add_argument(
        '--password',
        default='admin123',
        help='Admin user password (default: admin123)'
    )
    parser.add_argument(
        '--name',
        default='Admin User',
        help='Admin user full name (default: Admin User)'
    )
    
    args = parser.parse_args()
    
    logger.info('Starting user and role seeder...')
    
    db = SessionLocal()
    try:
        role_map, admin_user = seed_users_and_roles(
            db,
            admin_email=args.email,
            admin_password=args.password,
            admin_name=args.name
        )
        logger.info(f'User and role seeder completed successfully!')
        logger.info(f'Admin user: {admin_user.email} (ID: {admin_user.id})')
        logger.info(f'Roles created: {len(role_map)}')
        print(f'\n✓ Admin user created successfully!')
        print(f'  Email: {admin_user.email}')
        print(f'  Password: {args.password}')
        print(f'  Role: admin')
        print(f'\n⚠️  IMPORTANT: Change the default password after first login!')
    except Exception as e:
        logger.error(f'Failed to seed users and roles: {str(e)}', exc_info=True)
        sys.exit(1)
    finally:
        db.close()


if __name__ == '__main__':
    main()

