"""Schema reference for `integration.conf`.

Values are always returned as strings by `BaseConfig.get`. Type parsing
(int, int list, bool, rule-id map) is the caller's responsibility. The
format columns below are advisory conventions shared between producers
(wizard, installers, panel templates) and consumers, not runtime-enforced
schemas.

Validation today is narrow: `other/compatibility-check.sh` validates INI
syntax, `[paths] ui_path`, and the `panel_info` script at install time;
integration-script JSON outputs are validated at runtime via Cerberus
schemas under `panels/generic/users_script_schemas/`. All other keys are
read on demand and trusted.

Non-obvious `.get()` behavior:
- Missing file returns `None` (ConfigParser.read silently ignores missing
  paths; use `BaseConfig.exists()` to distinguish).
- Malformed INI propagates `configparser.Error`; `.get()` only catches
  `KeyError`.
- Section names are case-sensitive (ConfigParser default); option names
  are case-insensitive. Match the casing documented below.

Sections
--------

`[PAM]`
    - `SERVICE_NAME` (str): PAM service used for UI login
      authentication.

`[panel]`
    - `type` (str, `cpanel`|`plesk`|`directadmin`|`generic`):
      master switch for panel class selection.

`[panel_ports]`
    Comma-separated integer lists (e.g. `2082, 2095`). Empty or absent
    means "no ports of this class".

    - `http_ports`: ports the panel listens on for HTTP admin traffic.
    - `https_ports`: HTTPS equivalents.
    - `webshield_protected_ports`: subset of the above that WebShield
      should protect.

`[panel_login]`
    - `ossec_rules` (str, comma-separated `rule_id:bool` pairs, e.g.
      `11006:false,11009:true`): OSSEC rule IDs to auto-whitelist for
      panel-login events.

`[features]`
    Boolean feature flags. Conventional values: `true` / `false`
    (case-insensitive).

    - `webshield_enabled` (bool)
    - `cphulk_enabled` (bool)

`[smtp]`
    - `allow_users` (str, comma-separated list of usernames): system
      users allowed to send SMTP when the SMTP block feature is active.
    - `conflict_config_file` (str, absolute path): panel config file
      whose value toggles the SMTP-block conflict check.
    - `conflict_config_key` (str): key inside `conflict_config_file`
      that holds the conflicting setting.

`[web_server]`
    - `server_type` (str, `apache`|`nginx`|...): web server in use.
    - `modsec_audit_log` (str, absolute path): ModSecurity audit log
      file.
    - `modsec_audit_logdir` (str, absolute path): ModSecurity audit log
      directory (concurrent writer layout).
    - `graceful_restart_script` (str, command string): whitespace-split
      command used to gracefully restart the web server
      (e.g. `/usr/bin/systemctl restart apache2`).
    - `config_test_script` (str, command string): whitespace-split
      command used to validate the web server configuration before
      reload (e.g. `/usr/sbin/apache2ctl -t`).

`[integration_scripts]`
    Values are absolute paths to scripts executed by the agent as root.
    Populate with trusted, integrator-controlled paths only; do not
    interpolate user-controlled data.

    - `users` (str path): emits JSON user list.
    - `domains` (str path): emits JSON domain -> owner mapping.
    - `admins` (str path): emits JSON admin list.
    - `panel_info` (str path): emits JSON `{name, version, ...}`
      describing the panel.
    - `modsec_domain_config_script` (str path): emits per-domain
      ModSecurity overrides.

`[paths]`
    - `ui_path` (str, absolute path): document root for the standalone
      UI.
    - `ui_path_owner` (str, `user:group`): owner applied to UI files
      during install.

`[malware]`
    - `basedir` (str, **whitespace-separated** paths): base directories
      scanned for malware. Note the separator differs from port lists
      (whitespace here, comma for port lists).

`[metadata]`
    - `schema_version` (int): schema version number.
    - `created_by` (str, `wizard`|`agent`|`manual`): who wrote the file;
      useful for support triage.
"""

import os
from typing import Optional

from defence360agent.application.determine_hosting_panel import GP_FILE


class BaseConfig:
    @classmethod
    def exists(cls):
        return os.path.exists(cls._conf_path)

    @classmethod
    def to_dict(cls):
        from configparser import ConfigParser

        integration_conf = ConfigParser()
        integration_conf.read(cls._conf_path)

        return integration_conf

    @classmethod
    def get(cls, section: str, option: str) -> Optional[str]:
        """
        Return *option* value in *section* in config if exist,
        None otherwise.
        """
        try:
            return cls.to_dict()[section][option]
        except KeyError:
            return None


class IntegrationConfig(BaseConfig):
    _conf_path = GP_FILE


class ClIntegrationConfig(BaseConfig):
    _conf_path = "/opt/cpvendor/etc/integration.ini"
