"""
Who can reach which part of the CMS.

One map, used in two places: the sidebar hides what a user cannot open, and
the views refuse it. Hiding alone is decoration, so both matter.

System Administrator is the only role with access to everything, including the
platform itself. Every other role is scoped to its job.
"""
from apps.accounts.models import User

# Section keys are deliberately coarse. They describe areas of the panel, not
# individual pages, so a new page inherits the rules of the area it belongs to.
SECTION_PLATFORM   = 'platform'    # tenants, fleet, system, versions
SECTION_USERS      = 'users'       # staff accounts and roles
SECTION_SETTINGS   = 'settings'    # site settings, API keys, integrations
SECTION_COMMERCE   = 'commerce'    # products, orders, subscriptions
SECTION_FINANCE    = 'finance'     # invoices, expenses, CRM
SECTION_SALES      = 'sales'       # assessments and quotes
SECTION_SUPPORT    = 'support'     # tickets, chat, contact
SECTION_CONTENT    = 'content'     # homepage, insights, portfolio, services, media, FAQ
SECTION_ANALYTICS  = 'analytics'   # dashboard and reporting

ALL_SECTIONS = [
    SECTION_PLATFORM, SECTION_USERS, SECTION_SETTINGS, SECTION_COMMERCE,
    SECTION_FINANCE, SECTION_SALES, SECTION_SUPPORT, SECTION_CONTENT,
    SECTION_ANALYTICS,
]

ROLE_SECTIONS = {
    User.ROLE_SYSTEM_ADMIN: set(ALL_SECTIONS),

    User.ROLE_SUPER_ADMIN: {
        SECTION_USERS, SECTION_SETTINGS, SECTION_COMMERCE, SECTION_FINANCE,
        SECTION_SALES, SECTION_SUPPORT, SECTION_CONTENT, SECTION_ANALYTICS,
    },
    User.ROLE_BUSINESS_ADMIN: {
        SECTION_COMMERCE, SECTION_FINANCE, SECTION_SALES, SECTION_SUPPORT,
        SECTION_CONTENT, SECTION_ANALYTICS,
    },
    User.ROLE_FINANCE_ADMIN: {
        SECTION_COMMERCE, SECTION_FINANCE, SECTION_ANALYTICS,
    },
    User.ROLE_SUPPORT_AGENT: {
        SECTION_SALES, SECTION_SUPPORT, SECTION_ANALYTICS,
    },
    User.ROLE_CONTENT_MANAGER: {
        SECTION_CONTENT, SECTION_ANALYTICS,
    },
    User.ROLE_ANALYST: {
        SECTION_ANALYTICS,
    },
}

# Roles that may only look, never change. Enforced separately from section
# access, because an Analyst can open Analytics but must not post to it.
READ_ONLY_ROLES = {User.ROLE_ANALYST}


def sections_for(user):
    """Every section this user may open."""
    if not user or not getattr(user, 'is_authenticated', False):
        return set()
    if getattr(user, 'is_superuser', False):
        return set(ALL_SECTIONS)
    # An unrecognised role, for instance one left over from an older version of
    # this system, falls back to read only rather than locking the person out.
    return ROLE_SECTIONS.get(getattr(user, 'role', ''), ROLE_SECTIONS[User.ROLE_ANALYST])


def can_access(user, section):
    """True if this user may open the given section."""
    return section in sections_for(user)


def is_read_only(user):
    """True if this user may view but not submit."""
    if not user or not getattr(user, 'is_authenticated', False):
        return True
    if getattr(user, 'is_superuser', False):
        return False
    return getattr(user, 'role', '') in READ_ONLY_ROLES


# ─── URL name to section ────────────────────────────────────────────────────────
# Matching is by longest prefix, so `cms_tenant_invoice_send` picks up the
# `cms_tenant` rule without needing its own entry, and a route added later
# inherits the rules of the area it sits in.

URL_PREFIX_SECTIONS = [
    # Platform: the estate itself. System Administrator only.
    ('cms_tenant',              SECTION_PLATFORM),
    ('cms_fleet',               SECTION_PLATFORM),
    ('cms_health',              SECTION_PLATFORM),
    ('cms_system_info',         SECTION_PLATFORM),
    ('cms_version',             SECTION_PLATFORM),
    ('cms_upgrade_charge',      SECTION_PLATFORM),
    ('cms_backup',              SECTION_PLATFORM),
    ('cms_application',         SECTION_PLATFORM),
    # Tenant facing Plugins page. Same section as the Applications page it
    # replaces, so existing role access carries over unchanged.
    ('cms_tenant_plugin',       SECTION_PLATFORM),
    ('cms_marketplace',         SECTION_PLATFORM),
    ('cms_plugin',              SECTION_PLATFORM),

    # Staff accounts and roles
    ('cms_user',                SECTION_USERS),

    # Configuration
    ('cms_settings',            SECTION_SETTINGS),
    ('cms_security',            SECTION_SETTINGS),
    ('cms_email_template',      SECTION_SETTINGS),
    ('cms_legal_page',          SECTION_SETTINGS),
    ('cms_footer',              SECTION_SETTINGS),
    ('cms_social_link',         SECTION_SETTINGS),

    # Selling
    ('cms_product_interests',   SECTION_SALES),
    ('cms_product',             SECTION_COMMERCE),
    ('cms_order',               SECTION_COMMERCE),
    ('cms_subscription',        SECTION_COMMERCE),
    ('cms_auction',             SECTION_COMMERCE),

    # Money
    ('cms_expense',             SECTION_FINANCE),
    ('cms_crm',                 SECTION_FINANCE),
    ('cms_email_log',           SECTION_FINANCE),
    ('cms_email_resend',        SECTION_FINANCE),

    # Pipeline
    ('cms_assessment',          SECTION_SALES),

    # Support desk
    ('cms_ticket',              SECTION_SUPPORT),
    ('cms_chat',                SECTION_SUPPORT),

    # Site content
    ('cms_homepage',            SECTION_CONTENT),
    ('cms_hero',                SECTION_CONTENT),
    ('cms_about',               SECTION_CONTENT),
    ('cms_why',                 SECTION_CONTENT),
    ('cms_process',             SECTION_CONTENT),
    ('cms_service',             SECTION_CONTENT),
    ('cms_partner',             SECTION_CONTENT),
    ('cms_portfolio',           SECTION_CONTENT),
    ('cms_insight',             SECTION_CONTENT),
    ('cms_faq',                 SECTION_CONTENT),
    ('cms_testimonial',         SECTION_CONTENT),
    ('cms_media',               SECTION_CONTENT),
    ('cms_sort_items',          SECTION_CONTENT),

    # Reporting
    ('cms_dashboard',           SECTION_ANALYTICS),
    ('cms_analytics',           SECTION_ANALYTICS),
]

# Routes every signed-in member of staff may use, whatever their role.
OPEN_URL_NAMES = {
    'cms_login', 'cms_login_public', 'cms_logout', 'cms_my_profile',
    'cms_notifications_dismiss',
    # The dashboard is where every refusal redirects, so it must never be
    # refused itself. Blocking it would bounce a user in a loop and spit them
    # back out at the login page.
    'cms_dashboard',
}


def section_for_url(url_name):
    """The section a URL name belongs to, or None if it is open to everyone."""
    if not url_name or url_name in OPEN_URL_NAMES:
        return None
    best = None
    for prefix, section in URL_PREFIX_SECTIONS:
        if url_name.startswith(prefix) and (best is None or len(prefix) > len(best[0])):
            best = (prefix, section)
    return best[1] if best else None
