"""
Typer CLI exposed as `apexfastapi`.
"""
from __future__ import annotations

import asyncio
from pathlib import Path

import typer

from apex import __version__
from apex.core.config import get_settings
from apex.domain.services.user import UserService
from apex.infrastructure.database import AsyncSessionLocal

# Try to import migrate - may not exist in all setups
try:
    from apex.app.database.migrate import migrate
except ImportError:
    migrate = None

# Try to import custom fields - may not exist in all setups
try:
    from apex.app.custom_fields import get_custom_fields_summary
except ImportError:
    get_custom_fields_summary = None

cli = typer.Typer(name="apexfastapi", help="Apex FastAPI Boilerplate CLI")


@cli.command()
def version():
    typer.echo(f"apex-saas-framework {__version__}")


@cli.command()
def init(
    path: Path = typer.Argument(Path.cwd(), help="Project directory"),
    app_name: str = typer.Option("MyApp", "--name", "-n", help="Application name"),
):
    """
    Initialize a new Apex project with auto-generated models.py and app.py.
    
    This command creates:
    - models.py: Base models that you can extend with custom fields
    - app.py: FastAPI application with all routes configured
    - .env: Environment configuration file
    """
    path.mkdir(parents=True, exist_ok=True)
    
    # Generate models.py with proper structure
    models_py = path / "models.py"
    if not models_py.exists():
        models_content = '''"""
Your application models.

By default we expose Apex's built-in models so you can pass them into
`Apex(models=[...])` without duplicating table definitions.

If you want to add custom columns, create subclasses in a separate module and
override the dependency helpers to point at them.
"""
from apex.app.models.default import (
    Organization,
    OrganizationLocation,
    Permission,
    Role,
    User,
)

__all__ = ["Organization", "OrganizationLocation", "Permission", "Role", "User"]
'''
        models_py.write_text(models_content, encoding="utf-8")
        typer.echo(f"✅ Created {models_py}")

    # Generate app.py with proper structure
    app_py = path / "app.py"
    if not app_py.exists():
        app_content = f'''"""
{app_name} - FastAPI Application

This file is auto-generated by Apex. You can customize:
- Endpoint prefixes (e.g., change "/api/auth" to "/auth")
- Enable/disable routes
- Add custom routes
"""
from fastapi import Depends
from sqlalchemy.ext.asyncio import AsyncSession

from apex import Apex
from apex.api.v1.auth.router import get_auth_service, get_user_service
from apex.domain.services.auth import AuthService
from apex.domain.services.user import UserService
from apex.infrastructure.database import get_db
from models import Organization, OrganizationLocation, Permission, Role, User

# Create the app with your models
app = Apex(
    title="{app_name}",
    models=[User, Organization, OrganizationLocation, Role, Permission],
    auto_create_tables=True,  # Set to False if using migrations
).app


# Override services to use your custom models
async def custom_auth_service(
    db: AsyncSession = Depends(get_db),
) -> AuthService:
    """Provide AuthService using your User model."""
    return AuthService(session=db, user_model=User)


async def custom_user_service(
    db: AsyncSession = Depends(get_db),
) -> UserService:
    """Provide UserService using your User model."""
    return UserService(session=db, user_model=User)


# Override Apex defaults so routers use your models
app.dependency_overrides[get_auth_service] = custom_auth_service
app.dependency_overrides[get_user_service] = custom_user_service


# Customize endpoints here (optional)
# Example 1: Change endpoint prefixes using ApexConfig
# from apex import Apex, ApexConfig
# config = ApexConfig(auth_prefix="/auth", users_prefix="/users")
# app = Apex(config=config, models=[...]).app

# Example 2: Manually include routers with custom prefixes
# from apex.api.v1 import auth_router, users_router
# app.include_router(auth_router, prefix="/auth", tags=["Authentication"])
# app.include_router(users_router, prefix="/users", tags=["Users"])


if __name__ == "__main__":
    import uvicorn
    uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)
'''
        app_py.write_text(app_content, encoding="utf-8")
        typer.echo(f"✅ Created {app_py}")

    # Generate .env file
    env_path = path / ".env"
    if not env_path.exists():
        import secrets
        secret_key = secrets.token_urlsafe(32)
        env_content = f'''# Database Configuration
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/{app_name.lower().replace(" ", "_")}

# Security
SECRET_KEY={secret_key}

# PayPal (optional)
PAYPAL_CLIENT_ID=
PAYPAL_CLIENT_SECRET=

# Email (optional)
SENDGRID_API_KEY=
FROM_EMAIL=
'''
        env_path.write_text(env_content, encoding="utf-8")
        typer.echo(f"✅ Created {env_path}")

    # Generate requirements.txt
    requirements_txt = path / "requirements.txt"
    if not requirements_txt.exists():
        requirements_content = '''apex-saas-framework
uvicorn[standard]
python-dotenv
'''
        requirements_txt.write_text(requirements_content, encoding="utf-8")
        typer.echo(f"✅ Created {requirements_txt}")

    # Generate README.md
    readme_md = path / "README.md"
    if not readme_md.exists():
        readme_content = f'''# {app_name}

Built with [Apex SaaS Framework](https://github.com/your-repo/apex-saas-framework)

## Quick Start

1. Install dependencies:
   ```bash
   pip install -r requirements.txt
   ```

2. Configure database in `.env`:
   ```bash
   DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/dbname
   ```

3. Run migrations (if needed):
   ```bash
   apexfastapi migrate -m "Initial migration"
   ```

4. Start the server:
   ```bash
   python app.py
   # or
   uvicorn app:app --reload
   ```

## Adding Custom Fields

Edit `models.py` to add custom fields to your models:

```python
class User(BaseUser):
    __tablename__ = "users"
    
    # Add your custom fields
    department = Column(String(100))
    employee_id = Column(String(50), unique=True)
```

Then run:
```bash
apexfastapi migrate -m "Add custom fields"
```

## API Documentation

Once running, visit:
- Swagger UI: http://localhost:8000/docs
- ReDoc: http://localhost:8000/redoc

## Available Endpoints

- `POST /api/auth/signup` - User registration
- `POST /api/auth/login` - User login
- `GET /api/users/me` - Get current user
- `POST /api/auth/forgot-password` - Request password reset
- `POST /api/auth/reset-password` - Reset password

See `/docs` for complete API documentation.
'''
        readme_md.write_text(readme_content, encoding="utf-8")
        typer.echo(f"✅ Created {readme_md}")

    typer.echo(f"\n🎉 Project '{app_name}' initialized at {path}")
    typer.echo("\nNext steps:")
    typer.echo("  1. Configure DATABASE_URL in .env")
    typer.echo("  2. Run: python app.py")
    typer.echo("  3. Visit: http://localhost:8000/docs")


@cli.command("migrate")
def migrate_db(message: str = typer.Option("auto migration", "--message", "-m")):
    """Run database migrations with custom fields detection."""
    if migrate is None:
        typer.echo("❌ Migration not available. Make sure alembic is configured.")
        raise typer.Exit(1)
    
    # Try to detect custom fields from user's models.py
    try:
        import sys
        from pathlib import Path
        import importlib.util
        
        # Try to load models from current directory or parent
        models_file = Path.cwd() / "models.py"
        if not models_file.exists():
            models_file = Path.cwd().parent / "models.py"
        
        if models_file.exists() and get_custom_fields_summary:
            spec = importlib.util.spec_from_file_location("models", models_file)
            if spec and spec.loader:
                models_module = importlib.util.module_from_spec(spec)
                spec.loader.exec_module(models_module)
                
                # Get all model classes
                models = []
                for attr_name in dir(models_module):
                    attr = getattr(models_module, attr_name)
                    if (isinstance(attr, type) and 
                        hasattr(attr, '__tablename__') and 
                        attr_name not in ['BaseUser', 'BaseOrganization', 'BaseRole', 'BasePermission']):
                        models.append(attr)
                
                if models:
                    summary = get_custom_fields_summary(models)
                    if summary:
                        typer.echo("\n📋 Custom Fields Detected:")
                        for model_name, fields in summary.items():
                            typer.echo(f"  {model_name}:")
                            for field in fields:
                                nullable = "nullable" if field["nullable"] else "required"
                                typer.echo(f"    - {field['name']}: {field['type']} ({nullable})")
                        typer.echo()
                    else:
                        typer.echo("ℹ️  No custom fields detected. Using base models only.\n")
    except Exception as e:
        typer.echo(f"⚠️  Could not detect custom fields: {e}\n")
    
    # Run migration
    migrate(message)


@cli.command("create-superuser")
def create_superuser():
    """Create a superuser account."""
    email = typer.prompt("Email")
    password = typer.prompt("Password", hide_input=True, confirmation_prompt=True)
    first_name = typer.prompt("First name", default="")
    last_name = typer.prompt("Last name", default="")

    async def _create():
        # Try to import User model from user's models.py
        try:
            import sys
            from pathlib import Path
            import importlib.util
            
            models_file = Path.cwd() / "models.py"
            if not models_file.exists():
                models_file = Path.cwd().parent / "models.py"
            
            if models_file.exists():
                spec = importlib.util.spec_from_file_location("models", models_file)
                if spec and spec.loader:
                    models_module = importlib.util.module_from_spec(spec)
                    spec.loader.exec_module(models_module)
                    UserModel = getattr(models_module, "User", None)
            else:
                # Fallback to base model
                from apex.domain.models import BaseUser as UserModel
        except Exception:
            from apex.domain.models import BaseUser as UserModel
        
        async with AsyncSessionLocal() as session:
            service = UserService(session, UserModel)
            if await service.get_user_by_email(email):
                typer.echo("Superuser already exists.")
                return
            await service.create_user(
                email=email,
                password=password,
                first_name=first_name or None,
                last_name=last_name or None,
                is_active=True,
                is_verified=True,
                is_superuser=True,
            )
            await session.commit()
            typer.echo("✅ Superuser created successfully.")

    asyncio.run(_create())


@cli.command("custom-fields")
def show_custom_fields():
    """Show all custom fields detected in extended models."""
    if get_custom_fields_summary is None:
        typer.echo("❌ Custom fields detection not available.")
        raise typer.Exit(1)
    
    try:
        import sys
        from pathlib import Path
        import importlib.util
        
        # Try to load models from current directory
        models_file = Path.cwd() / "models.py"
        if not models_file.exists():
            models_file = Path.cwd().parent / "models.py"
        
        if not models_file.exists():
            typer.echo("ℹ️  No models.py found.")
            typer.echo("   Create models.py and extend base models to add custom fields:")
            typer.echo("   Example: class User(BaseUser):")
            typer.echo("               __tablename__ = 'users'")
            typer.echo("               department = Column(String(100))")
            return
        
        spec = importlib.util.spec_from_file_location("models", models_file)
        if spec and spec.loader:
            models_module = importlib.util.module_from_spec(spec)
            spec.loader.exec_module(models_module)
            
            # Get all model classes
            models = []
            for attr_name in dir(models_module):
                attr = getattr(models_module, attr_name)
                if (isinstance(attr, type) and 
                    hasattr(attr, '__tablename__') and 
                    attr_name not in ['BaseUser', 'BaseOrganization', 'BaseRole', 'BasePermission']):
                    models.append(attr)
            
            if not models:
                typer.echo("ℹ️  No custom models found in models.py")
                return
            
            summary = get_custom_fields_summary(models)
            
            if not summary:
                typer.echo("ℹ️  No custom fields detected.")
                typer.echo("   Extend base models to add custom fields:")
                typer.echo("   Example: class User(BaseUser):")
                typer.echo("               __tablename__ = 'users'")
                typer.echo("               department = Column(String(100))")
                return
            
            typer.echo("📋 Custom Fields Summary:\n")
            for model_name, fields in summary.items():
                typer.echo(f"  {model_name}:")
                for field in fields:
                    nullable = "nullable" if field["nullable"] else "required"
                    default_info = f", default={field['default']}" if field["default"] is not None else ""
                    typer.echo(f"    • {field['name']}: {field['type']} ({nullable}{default_info})")
            typer.echo()
            
            typer.echo("💡 Tip: Run 'apexfastapi migrate -m \"description\"' to generate migrations for these fields.")
    except Exception as e:
        typer.echo(f"❌ Error detecting custom fields: {e}")
        raise typer.Exit(1)


@cli.command()
def check():
    settings = get_settings()
    typer.echo("Configuration check:")
    typer.echo(f"  Database URL: {settings.DATABASE_URL}")
    typer.echo(f"  Debug mode: {settings.DEBUG}")
    typer.echo(
        "  Secret key set: "
        + ("Yes" if settings.SECRET_KEY != "change-this-secret-key-in-production" else "No (WARNING!)")
    )


def main():
    cli()


if __name__ == "__main__":
    main()

