"""Organization management generator for Prism.

Generates organization models, membership, services, schemas, routes,
and middleware for multi-tenant organization support with RBAC.
"""

from __future__ import annotations

from pathlib import Path

from prisme.generators.base import GeneratedFile, GeneratorBase
from prisme.spec.stack import FileStrategy
from prisme.utils.case_conversion import to_snake_case
from prisme.utils.template_engine import TemplateRenderer


class OrganizationGenerator(GeneratorBase):
    """Generates organization management backend infrastructure.

    Produces:
    - Organization SQLAlchemy model
    - OrganizationMembership model (user-org join with role)
    - OrganizationInvitation model
    - Organization service (CRUD + member management)
    - Organization schemas (Pydantic request/response)
    - Organization REST routes
    - Organization middleware (org context, permission checks)
    - Module init file
    """

    REQUIRED_TEMPLATES = [
        "backend/organization/org_model.py.jinja2",
        "backend/organization/org_membership_model.py.jinja2",
        "backend/organization/org_invitation_model.py.jinja2",
        "backend/organization/org_service.py.jinja2",
        "backend/organization/org_schemas.py.jinja2",
        "backend/organization/org_routes.py.jinja2",
        "backend/organization/org_middleware.py.jinja2",
        "backend/organization/org_init.py.jinja2",
    ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Skip if auth or organization is not enabled
        if not self.auth_config.enabled or not self.auth_config.organization.enabled:
            self.skip_generation = True
            return

        self.renderer = TemplateRenderer()
        self.renderer.validate_templates_exist(self.REQUIRED_TEMPLATES)

        backend_base = Path(self.generator_config.backend_output)
        package_name = self.get_package_name()
        package_base = backend_base / package_name

        self.org_base = package_base / "organization"
        self.models_path = package_base / "models"
        self.schemas_path = package_base / "schemas"
        self.routes_base = package_base / "api" / "rest"
        self.middleware_path = package_base / "middleware"

    def _get_common_context(self) -> dict:
        """Build template context for organization templates."""
        config = self.auth_config
        org_config = config.organization
        project_name = self.get_package_name()
        user_model = config.user_model
        user_model_snake = to_snake_case(user_model)

        return {
            "project_name": project_name,
            "user_model": user_model,
            "user_model_snake": user_model_snake,
            "username_field": config.username_field,
            "org_roles": [
                {
                    "name": role.name,
                    "permissions": role.permissions,
                    "description": role.description or "",
                }
                for role in org_config.roles
            ],
            "default_org_role": org_config.default_role,
            "max_members_per_org": org_config.max_members_per_org,
            "max_orgs_per_user": org_config.max_orgs_per_user,
            "allow_multiple_orgs": org_config.allow_multiple_orgs,
            "require_org_context": org_config.require_org_context,
            "invitation_expiry_hours": org_config.invitation_expiry_hours,
            "slug_field": org_config.slug_field,
            "has_email_service": config.has_email_features,
        }

    def generate_files(self) -> list[GeneratedFile]:
        """Generate all organization-related files."""
        if getattr(self, "skip_generation", False):
            return []

        return [
            self._generate_org_model(),
            self._generate_membership_model(),
            self._generate_invitation_model(),
            self._generate_org_service(),
            self._generate_org_schemas(),
            self._generate_org_routes(),
            self._generate_org_middleware(),
            self._generate_org_init(),
        ]

    def _generate_org_model(self) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/organization/org_model.py.jinja2",
            context=self._get_common_context(),
        )
        return GeneratedFile(
            path=self.org_base / "org_model.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Organization database model",
        )

    def _generate_membership_model(self) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/organization/org_membership_model.py.jinja2",
            context=self._get_common_context(),
        )
        return GeneratedFile(
            path=self.org_base / "org_membership_model.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Organization membership model",
        )

    def _generate_invitation_model(self) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/organization/org_invitation_model.py.jinja2",
            context=self._get_common_context(),
        )
        return GeneratedFile(
            path=self.org_base / "org_invitation_model.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Organization invitation model",
        )

    def _generate_org_service(self) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/organization/org_service.py.jinja2",
            context=self._get_common_context(),
        )
        return GeneratedFile(
            path=self.org_base / "org_service.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Organization service",
        )

    def _generate_org_schemas(self) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/organization/org_schemas.py.jinja2",
            context=self._get_common_context(),
        )
        return GeneratedFile(
            path=self.schemas_path / "organization.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Organization API schemas",
        )

    def _generate_org_routes(self) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/organization/org_routes.py.jinja2",
            context=self._get_common_context(),
        )
        return GeneratedFile(
            path=self.routes_base / "organization.py",
            content=content,
            strategy=FileStrategy.GENERATE_ONCE,
            description="Organization API routes",
        )

    def _generate_org_middleware(self) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/organization/org_middleware.py.jinja2",
            context=self._get_common_context(),
        )
        return GeneratedFile(
            path=self.middleware_path / "organization.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Organization middleware",
        )

    def _generate_org_init(self) -> GeneratedFile:
        content = self.renderer.render_file(
            "backend/organization/org_init.py.jinja2",
            context=self._get_common_context(),
        )
        return GeneratedFile(
            path=self.org_base / "__init__.py",
            content=content,
            strategy=FileStrategy.ALWAYS_OVERWRITE,
            description="Organization module init",
        )
