#!/usr/bin/env python
"""
Django-Cast quickstart command.

Creates a new Django project with django-cast pre-configured.
"""

import argparse
import os
import secrets
import shutil
import subprocess
import sys
import threading
import time
import webbrowser
from pathlib import Path
from textwrap import dedent


def create_project_structure(project_name: str, target_dir: Path) -> None:
    """Create the basic project directory structure."""
    # Create main directories
    project_dir = target_dir / project_name
    project_dir.mkdir(parents=True, exist_ok=True)

    # Create app directory
    app_dir = project_dir / project_name
    app_dir.mkdir(exist_ok=True)

    # Create empty __init__.py
    (app_dir / "__init__.py").touch()

    # Create templates directory
    templates_dir = app_dir / "templates"
    templates_dir.mkdir(exist_ok=True)

    # Create static files directory
    static_dir = project_dir / "static"
    static_dir.mkdir(exist_ok=True)

    # Create media directory
    media_dir = project_dir / "media"
    media_dir.mkdir(exist_ok=True)


def create_settings_file(project_name: str, target_dir: Path) -> None:
    """Create settings.py with django-cast configuration."""
    settings_content = dedent(f'''
        """
        Django settings for {project_name} project.

        Generated by django-cast quickstart.
        """

        from pathlib import Path
        from cast import CAST_APPS, CAST_MIDDLEWARE

        # Build paths inside the project like this: BASE_DIR / 'subdir'.
        BASE_DIR = Path(__file__).resolve().parent.parent

        # SECURITY WARNING: keep the secret key used in production secret!
        SECRET_KEY = "{secrets.token_urlsafe(50)}"

        # SECURITY WARNING: don't run with debug turned on in production!
        DEBUG = True

        ALLOWED_HOSTS = []

        # Application definition
        INSTALLED_APPS = [
            "django.contrib.admin",
            "django.contrib.auth",
            "django.contrib.contenttypes",
            "django.contrib.sessions",
            "django.contrib.messages",
            "django.contrib.staticfiles",
            "django.contrib.sites",
        ] + CAST_APPS

        MIDDLEWARE = [
            "django.middleware.security.SecurityMiddleware",
            "django.contrib.sessions.middleware.SessionMiddleware",
            "django.middleware.common.CommonMiddleware",
            "django.middleware.csrf.CsrfViewMiddleware",
            "django.contrib.auth.middleware.AuthenticationMiddleware",
            "django.contrib.messages.middleware.MessageMiddleware",
            "django.middleware.clickjacking.XFrameOptionsMiddleware",
        ] + CAST_MIDDLEWARE

        ROOT_URLCONF = "{project_name}.urls"

        TEMPLATES = [
            {{
                "BACKEND": "django.template.backends.django.DjangoTemplates",
                "DIRS": [BASE_DIR / "{project_name}" / "templates"],
                "APP_DIRS": True,
                "OPTIONS": {{
                    "context_processors": [
                        "django.template.context_processors.debug",
                        "django.template.context_processors.request",
                        "django.contrib.auth.context_processors.auth",
                        "django.contrib.messages.context_processors.messages",
                    ],
                }},
            }},
        ]

        WSGI_APPLICATION = "{project_name}.wsgi.application"

        # Database
        DATABASES = {{
            "default": {{
                "ENGINE": "django.db.backends.sqlite3",
                "NAME": BASE_DIR / "db.sqlite3",
            }}
        }}

        # Password validation
        AUTH_PASSWORD_VALIDATORS = [
            {{
                "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
            }},
            {{
                "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
            }},
            {{
                "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
            }},
            {{
                "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
            }},
        ]

        # Internationalization
        LANGUAGE_CODE = "en-us"
        TIME_ZONE = "UTC"
        USE_I18N = True
        USE_TZ = True

        # Static files (CSS, JavaScript, Images)
        STATIC_URL = "static/"
        STATIC_ROOT = BASE_DIR / "static"

        # Media files
        MEDIA_URL = "media/"
        MEDIA_ROOT = BASE_DIR / "media"

        # Default primary key field type
        DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

        # Site ID (required by django.contrib.sites)
        SITE_ID = 1

        # Wagtail settings
        WAGTAIL_SITE_NAME = "{project_name}"

        # Comments settings
        COMMENTS_APP = "fluent_comments"
        FLUENT_COMMENTS_EXCLUDE_FIELDS = ("email", "url", "title")
        CAST_COMMENTS_ENABLED = True

        # Crispy forms
        CRISPY_TEMPLATE_PACK = "bootstrap4"
        CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap4"

        # Django Vite configuration
        # For development, set dev_mode to True
        # For production, set dev_mode to False and ensure manifest.json exists
        DJANGO_VITE = {{
            "cast": {{
                "dev_mode": False,
                "static_url_prefix": "cast/vite/",
                "manifest_path": BASE_DIR / "static" / "cast" / "vite" / "manifest.json",
            }}
        }}
    ''').strip()

    settings_file = target_dir / project_name / project_name / "settings.py"
    settings_file.write_text(settings_content)


def create_urls_file(project_name: str, target_dir: Path) -> None:
    """Create urls.py with django-cast URL configuration."""
    urls_content = dedent(f'''
        """
        URL configuration for {project_name} project.
        """

        from django.conf import settings
        from django.contrib import admin
        from django.urls import include, path
        from wagtail import urls as wagtail_urls
        from wagtail.admin import urls as wagtailadmin_urls
        from wagtail.documents import urls as wagtaildocs_urls

        urlpatterns = [
            # Django admin
            path("admin/", admin.site.urls),

            # Wagtail admin
            path("cms/", include(wagtailadmin_urls)),

            # Wagtail documents
            path("documents/", include(wagtaildocs_urls)),

            # Cast URLs
            path("cast/", include("cast.urls", namespace="cast")),

            # Comments
            path("comments/", include("fluent_comments.urls")),

            # Wagtail pages (this should be last)
            path("", include(wagtail_urls)),
        ]

        if settings.DEBUG:
            from django.conf.urls.static import static
            from django.contrib.staticfiles.urls import staticfiles_urlpatterns

            # Serve static and media files from development server
            urlpatterns += staticfiles_urlpatterns()
            urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    ''').strip()

    urls_file = target_dir / project_name / project_name / "urls.py"
    urls_file.write_text(urls_content)


def create_wsgi_file(project_name: str, target_dir: Path) -> None:
    """Create wsgi.py file."""
    wsgi_content = dedent(f'''
        """
        WSGI config for {project_name} project.
        """

        import os

        from django.core.wsgi import get_wsgi_application

        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{project_name}.settings")

        application = get_wsgi_application()
    ''').strip()

    wsgi_file = target_dir / project_name / project_name / "wsgi.py"
    wsgi_file.write_text(wsgi_content)


def create_manage_py(project_name: str, target_dir: Path) -> None:
    """Create manage.py file."""
    manage_content = dedent(f'''
        #!/usr/bin/env python
        """Django's command-line utility for administrative tasks."""
        import os
        import sys

        if __name__ == "__main__":
            os.environ.setdefault("DJANGO_SETTINGS_MODULE", "{project_name}.settings")
            try:
                from django.core.management import execute_from_command_line
            except ImportError as exc:
                raise ImportError(
                    "Couldn't import Django. Are you sure it's installed and "
                    "available on your PYTHONPATH environment variable? Did you "
                    "forget to activate a virtual environment?"
                ) from exc
            execute_from_command_line(sys.argv)
    ''').strip()

    manage_file = target_dir / project_name / "manage.py"
    manage_file.write_text(manage_content)
    # Make it executable
    manage_file.chmod(0o755)


def create_base_template(project_name: str, target_dir: Path) -> None:
    """Create a basic base.html template."""
    template_content = dedent("""
        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="utf-8">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <title>{% block title %}{% endblock %} - {{ settings.WAGTAIL_SITE_NAME }}</title>
            <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
            {% block extra_css %}{% endblock %}
        </head>
        <body>
            <nav class="navbar navbar-expand-lg navbar-light bg-light">
                <div class="container">
                    <a class="navbar-brand" href="/">{{ settings.WAGTAIL_SITE_NAME }}</a>
                </div>
            </nav>

            <main class="container my-4">
                {% block content %}{% endblock %}
            </main>

            <footer class="container my-4 text-center text-muted">
                <p>Powered by Django-Cast</p>
            </footer>

            <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
            {% block extra_js %}{% endblock %}
        </body>
        </html>
    """).strip()

    template_file = target_dir / project_name / project_name / "templates" / "base.html"
    template_file.write_text(template_content)


def run_migrations(project_dir: Path) -> None:
    """Run Django migrations."""
    print("\nRunning migrations...")
    manage_py = project_dir / "manage.py"

    # Run makemigrations for sites app first (if needed)
    subprocess.run([sys.executable, str(manage_py), "migrate"], check=True)


def collect_static_files(project_dir: Path) -> None:
    """Run Django collectstatic command."""
    print("\nCollecting static files...")
    manage_py = project_dir / "manage.py"

    # Run collectstatic with --noinput to avoid prompts
    subprocess.run([sys.executable, str(manage_py), "collectstatic", "--noinput"], check=True)


def open_browser_delayed(url: str, delay: float = 5.0) -> None:
    """Open browser after a delay to allow server to start."""

    def _open():
        time.sleep(delay)
        print(f"\nOpening browser to {url}")
        print("Login with username: user, password: password")
        webbrowser.open(url)

    thread = threading.Thread(target=_open)
    thread.daemon = True
    thread.start()


def create_superuser(project_dir: Path, auto_create: bool = False) -> None:
    """Create superuser either automatically or interactively."""
    manage_py = project_dir / "manage.py"

    if auto_create:
        print("\nCreating superuser with default credentials...")
        print("Username: user")
        print("Password: password")
        print("Email: user@example.com")

        # Create superuser using shell command
        create_user_cmd = """
from django.contrib.auth import get_user_model
User = get_user_model()
if not User.objects.filter(username='user').exists():
    User.objects.create_superuser('user', 'user@example.com', 'password')
    print('Superuser created successfully!')
else:
    print('Superuser already exists.')
"""
        subprocess.run([sys.executable, str(manage_py), "shell", "-c", create_user_cmd], check=True)
    else:
        print("\nCreating superuser account...")
        print("You'll need this to access the Wagtail admin at /cms/")
        subprocess.run([sys.executable, str(manage_py), "createsuperuser"], check=True)


def main():
    """Main entry point for the quickstart command."""
    parser = argparse.ArgumentParser(
        description="Create a new Django project with django-cast pre-configured.",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=dedent("""
        Examples:
          django-cast-quickstart mysite                    # Creates project with default superuser (user/password)
          django-cast-quickstart mysite --interactive-superuser  # Prompts for custom credentials
          django-cast-quickstart mysite --no-superuser     # Skip superuser creation
        """),
    )

    parser.add_argument("project_name", help="Name of the Django project to create")

    parser.add_argument(
        "--interactive-superuser",
        action="store_true",
        help="Prompt for superuser credentials instead of using defaults (user/password)",
    )

    parser.add_argument("--no-superuser", action="store_true", help="Skip superuser creation entirely")

    args = parser.parse_args()

    if args.interactive_superuser and args.no_superuser:
        parser.error("Cannot use --interactive-superuser and --no-superuser together")

    project_name = args.project_name

    # Validate project name
    if not project_name.isidentifier():
        print(f"Error: '{project_name}' is not a valid Python identifier.")
        print("Project name must start with a letter and contain only letters, numbers, and underscores.")
        sys.exit(1)

    # Get target directory
    target_dir = Path.cwd()
    project_path = target_dir / project_name

    if project_path.exists():
        print(f"Error: Directory '{project_name}' already exists.")
        sys.exit(1)

    print(f"Creating Django-Cast project '{project_name}'...")

    try:
        # Create project structure
        create_project_structure(project_name, target_dir)

        # Create configuration files
        create_settings_file(project_name, target_dir)
        create_urls_file(project_name, target_dir)
        create_wsgi_file(project_name, target_dir)
        create_manage_py(project_name, target_dir)
        create_base_template(project_name, target_dir)

        # Run migrations
        run_migrations(project_path)

        # Collect static files
        collect_static_files(project_path)

        # Create superuser based on arguments
        if not args.no_superuser:
            # Default is auto-create, use interactive only if explicitly requested
            auto_create = not args.interactive_superuser
            create_superuser(project_path, auto_create=auto_create)
        else:
            print("\nSkipping superuser creation.")

        print(f"\nSuccess! Created Django-Cast project at {project_path}")

        # Show login credentials if auto-created
        if not args.no_superuser and not args.interactive_superuser:
            print("\nDefault superuser credentials:")
            print("  Username: user")
            print("  Password: password")
            print("\n⚠️  WARNING: Change these default credentials in production!")

        # Change to project directory
        os.chdir(project_path)
        print(f"\nChanged to project directory: {project_path}")

        # Start the development server
        print("\nStarting development server...")
        print("Press Ctrl+C to stop the server")

        # Open browser to Wagtail admin after delay
        admin_url = "http://localhost:8000/cms/"
        print("\nThe browser will open automatically in a few seconds...")
        open_browser_delayed(admin_url, delay=5.0)

        # Run the development server
        manage_py = project_path / "manage.py"
        subprocess.run([sys.executable, str(manage_py), "runserver"])

    except Exception as e:
        print(f"\nError: {e}")
        # Clean up on error
        if project_path.exists():
            shutil.rmtree(project_path)
        sys.exit(1)


if __name__ == "__main__":
    main()
