from pypos.core.utils.config_utils import (
    get_sync_watch_tables,
    read_app_settings,
    read_endpoint_config,
)
from pypos.modules.dashboard.config.dashboard_config import (
    DASHBOARD_APP_KEYS,
    DASHBOARD_DEFAULTS,
    DASHBOARD_ENDPOINT_KEYS,
    DASHBOARD_LAYOUT_KEYS,
)


class DashboardConfigService:
    def __init__(self):
        pass

    def _app_cfg(self) -> dict:
        cfg = read_app_settings()
        return cfg if isinstance(cfg, dict) else {}

    def _endpoint_cfg(self) -> dict:
        cfg = read_endpoint_config()
        return cfg if isinstance(cfg, dict) else {}

    def _get_int(self, cfg: dict, key: str, default: int, min_value: int = None) -> int:
        try:
            value = int(cfg.get(key, default))
        except (TypeError, ValueError, KeyError, AttributeError, RuntimeError, OSError, LookupError, ArithmeticError, ImportError):
            value = int(default)
        if min_value is not None:
            value = max(min_value, value)
        return value

    def _get_str(self, cfg: dict, key: str, default: str = "") -> str:
        return str(cfg.get(key, default) or default)

    # edited by glg
    def _get_float(self, cfg: dict, key: str, default: float, min_value: float = None) -> float:
        try:
            value = float(cfg.get(key, default))
        except (TypeError, ValueError, KeyError, AttributeError, RuntimeError, OSError, LookupError, ArithmeticError, ImportError):
            value = float(default)
        if min_value is not None:
            value = max(float(min_value), value)
        return float(value)

    def get_api_base_url(self) -> str:
        cfg = self._endpoint_cfg()
        return self._get_str(cfg, DASHBOARD_ENDPOINT_KEYS["api_base_url"], "").rstrip("/")

    def get_ui_assets_endpoint(self) -> str:
        cfg = self._endpoint_cfg()
        endpoint = self._get_str(
            cfg,
            DASHBOARD_ENDPOINT_KEYS["ui_assets_endpoint"],
            DASHBOARD_DEFAULTS["ui_assets_endpoint"],
        ).strip()
        if endpoint and not endpoint.startswith("/"):
            endpoint = "/" + endpoint
        return endpoint

    def get_request_timeout(self) -> int:
        cfg = self._endpoint_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_ENDPOINT_KEYS["request_timeout"],
            DASHBOARD_DEFAULTS["request_timeout"],
            min_value=1,
        )

    def get_auto_sync_master_minutes(self) -> int:
        cfg = self._app_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_APP_KEYS["auto_sync_master_minutes"],
            DASHBOARD_DEFAULTS["auto_sync_master_minutes"],
            min_value=1,
        )

    # edited by glg
    def get_auto_sync_probe_interval_seconds(self) -> int:
        cfg = self._app_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_APP_KEYS["auto_sync_probe_interval_seconds"],
            DASHBOARD_DEFAULTS["auto_sync_probe_interval_seconds"],
            min_value=15,
        )

    # edited by glg
    def get_auto_sync_notify_reminder_minutes(self) -> int:
        cfg = self._app_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_APP_KEYS["auto_sync_notify_reminder_minutes"],
            DASHBOARD_DEFAULTS["auto_sync_notify_reminder_minutes"],
            min_value=1,
        )

    def get_auto_sync_start_delay_seconds(self) -> int:
        cfg = self._app_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_APP_KEYS["auto_sync_start_delay_seconds"],
            DASHBOARD_DEFAULTS["auto_sync_start_delay_seconds"],
            min_value=0,
        )

    def get_sync_tables(self) -> list:
        cfg = self._app_cfg()
        tables = cfg.get(DASHBOARD_APP_KEYS["sync_tables"])
        return tables if isinstance(tables, list) else []

    def get_sync_watch_tables(self) -> list:
        return get_sync_watch_tables(self._app_cfg())

    def get_export_json_interval_minutes(self) -> int:
        cfg = self._app_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_APP_KEYS["export_json_interval_minutes"],
            DASHBOARD_DEFAULTS["export_json_interval_minutes"],
            min_value=1,
        )

    # edited by glg
    def get_online_poll_interval_ms(self) -> int:
        cfg = self._app_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_APP_KEYS["online_poll_interval_ms"],
            DASHBOARD_DEFAULTS["online_poll_interval_ms"],
            # edited by glg
            # Guard minimum agar polling indikator tidak terlalu agresif.
            min_value=5000,
        )

    # edited by glg
    def get_online_probe_timeout_sec(self) -> float:
        cfg = self._app_cfg()
        return self._get_float(
            cfg,
            DASHBOARD_APP_KEYS["online_probe_timeout_sec"],
            DASHBOARD_DEFAULTS["online_probe_timeout_sec"],
            min_value=0.2,
        )

    def is_export_on_close_enabled(self) -> bool:
        cfg = self._app_cfg()
        return (
            self._get_int(
                cfg,
                DASHBOARD_APP_KEYS["export_on_close"],
                DASHBOARD_DEFAULTS["export_on_close"],
                min_value=0,
            )
            == 1
        )

    # edited by glg
    def is_export_on_settlement_enabled(self) -> bool:
        cfg = self._app_cfg()
        return (
            self._get_int(
                cfg,
                DASHBOARD_APP_KEYS["export_on_settlement"],
                DASHBOARD_DEFAULTS["export_on_settlement"],
                min_value=0,
            )
            == 1
        )

    # edited by glg
    def get_settlement_delivery_mode(self) -> str:
        cfg = self._app_cfg()
        mode = self._get_str(
            cfg,
            DASHBOARD_APP_KEYS["settlement_delivery_mode"],
            DASHBOARD_DEFAULTS["settlement_delivery_mode"],
        ).strip().lower()
        if mode not in {"dual", "direct_only", "export_only"}:
            return "dual"
        return mode

    # edited by glg
    # Mode direct push aktif hanya jika:
    # - settlement_delivery_mode bukan export_only
    # - settlement_direct_enabled = 1
    def is_settlement_direct_push_enabled(self) -> bool:
        if self.get_settlement_delivery_mode() == "export_only":
            return False
        cfg = self._app_cfg()
        return (
            self._get_int(
                cfg,
                DASHBOARD_APP_KEYS["settlement_direct_enabled"],
                DASHBOARD_DEFAULTS["settlement_direct_enabled"],
                min_value=0,
            )
            == 1
        )

    # edited by glg
    # direct_only hanya dianggap aktif saat direct push memang diaktifkan.
    # Ini mencegah kehilangan data settlement bila setting mode salah.
    def is_settlement_direct_only_mode(self) -> bool:
        if self.get_settlement_delivery_mode() != "direct_only":
            return False
        return bool(self.is_settlement_direct_push_enabled())

    # edited by glg
    def is_export_replay_on_startup_enabled(self) -> bool:
        cfg = self._app_cfg()
        return (
            self._get_int(
                cfg,
                DASHBOARD_APP_KEYS["export_replay_on_startup_enabled"],
                DASHBOARD_DEFAULTS["export_replay_on_startup_enabled"],
                min_value=0,
            )
            == 1
        )

    # edited by glg
    def get_export_replay_on_startup_delay_ms(self) -> int:
        cfg = self._app_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_APP_KEYS["export_replay_on_startup_delay_ms"],
            DASHBOARD_DEFAULTS["export_replay_on_startup_delay_ms"],
            min_value=0,
        )

    # edited by glg
    def is_export_replay_on_startup_require_online(self) -> bool:
        cfg = self._app_cfg()
        return (
            self._get_int(
                cfg,
                DASHBOARD_APP_KEYS["export_replay_on_startup_require_online"],
                DASHBOARD_DEFAULTS["export_replay_on_startup_require_online"],
                min_value=0,
            )
            == 1
        )

    # edited by glg
    def get_export_replay_on_startup_upload_batch_limit(self) -> int:
        cfg = self._app_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_APP_KEYS["export_replay_on_startup_upload_batch_limit"],
            DASHBOARD_DEFAULTS["export_replay_on_startup_upload_batch_limit"],
            min_value=1,
        )

    # edited by glg
    def is_export_requeue_failed_transient_on_startup_enabled(self) -> bool:
        cfg = self._app_cfg()
        return (
            self._get_int(
                cfg,
                DASHBOARD_APP_KEYS["export_requeue_failed_transient_on_startup"],
                DASHBOARD_DEFAULTS["export_requeue_failed_transient_on_startup"],
                min_value=0,
            )
            == 1
        )

    # edited by glg
    def get_export_requeue_failed_transient_limit(self) -> int:
        cfg = self._app_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_APP_KEYS["export_requeue_failed_transient_limit"],
            DASHBOARD_DEFAULTS["export_requeue_failed_transient_limit"],
            min_value=1,
        )

    # edited by glg
    def get_export_requeue_failed_transient_max_age_hours(self) -> int:
        cfg = self._app_cfg()
        return self._get_int(
            cfg,
            DASHBOARD_APP_KEYS["export_requeue_failed_transient_max_age_hours"],
            DASHBOARD_DEFAULTS["export_requeue_failed_transient_max_age_hours"],
            min_value=1,
        )

    def get_ui_layout_config(self) -> dict:
        cfg = self._app_cfg()
        logo_size = self._get_int(
            cfg,
            DASHBOARD_LAYOUT_KEYS["logo_size"],
            DASHBOARD_DEFAULTS["logo_size"],
            min_value=1,
        )
        logo_width = self._get_int(
            cfg,
            DASHBOARD_LAYOUT_KEYS["logo_width"],
            DASHBOARD_DEFAULTS["logo_width"],
            min_value=logo_size,
        )
        sidebar_width = self._get_int(
            cfg,
            DASHBOARD_LAYOUT_KEYS["sidebar_width"],
            DASHBOARD_DEFAULTS["sidebar_width"],
            min_value=1,
        )
        sidebar_btn_height = self._get_int(
            cfg,
            DASHBOARD_LAYOUT_KEYS["sidebar_btn_height"],
            DASHBOARD_DEFAULTS["sidebar_btn_height"],
            min_value=1,
        )
        sidebar_spacing = self._get_int(
            cfg,
            DASHBOARD_LAYOUT_KEYS["sidebar_spacing"],
            DASHBOARD_DEFAULTS["sidebar_spacing"],
            min_value=0,
        )
        sidebar_margin = self._get_int(
            cfg,
            DASHBOARD_LAYOUT_KEYS["sidebar_margin"],
            DASHBOARD_DEFAULTS["sidebar_margin"],
            min_value=0,
        )
        status_icon_box = self._get_int(
            cfg,
            DASHBOARD_LAYOUT_KEYS["status_icon_box"],
            DASHBOARD_DEFAULTS["status_icon_box"],
            min_value=1,
        )
        status_icon_size = self._get_int(
            cfg,
            DASHBOARD_LAYOUT_KEYS["status_icon_size"],
            DASHBOARD_DEFAULTS["status_icon_size"],
            min_value=1,
        )
        if status_icon_size > status_icon_box:
            status_icon_size = status_icon_box
        return {
            "logo_size": logo_size,
            "logo_width": logo_width,
            "sidebar_width": sidebar_width,
            "sidebar_btn_height": sidebar_btn_height,
            "sidebar_spacing": sidebar_spacing,
            "sidebar_margin": sidebar_margin,
            "status_icon_box": status_icon_box,
            "status_icon_size": status_icon_size,
        }
