import requests
import uuid

from pypos.core.base_service import BaseService
from pypos.core.utils.device_utils import get_active_device_info, get_device_id
from pypos.core.utils.http_json_utils import parse_json_response
from pypos.modules.penjualan.config.penjualan_config import (
    PENJUALAN_ENDPOINT_KEYS,
    build_endpoint_url,
    get_penjualan_endpoint_config,
    get_preorder_probe_timeout_sec,
    get_request_timeout,
)
from pypos.modules.penjualan.services.error_envelope_service import ErrorEnvelopeService


class PreorderApiService(BaseService):
    def __init__(self, http_client=None):
        super().__init__(http_client=http_client or requests)

    # edited by glg
    def _generate_trace_id(self, scope: str = "preorder") -> str:
        return f"pre-{str(scope or 'preorder').strip().lower()}-{uuid.uuid4().hex[:10]}"

    # edited by glg
    def _error_payload(self, *, trace_id: str, reason: str, error_code: str, message: str = ""):
        return ErrorEnvelopeService.build_error(
            status=0,
            reason=reason,
            error_code=error_code,
            trace_id=trace_id,
            message=message,
            code_prefix="PREORDER",
        )

    def _as_positive_int(self, value, default=0):
        try:
            parsed = int(str(value).strip())
        except (TypeError, ValueError):
            parsed = int(default or 0)
        return parsed if parsed > 0 else 0

    # edited by glg
    def _resolve_request_identity(self, user_info):
        user = user_info if isinstance(user_info, dict) else {}
        device_info = get_active_device_info(get_device_id()) or {}
        machine_id = str(
            user.get("machine_id")
            or device_info.get("machine_id")
            or get_device_id()
            or ""
        ).strip()
        kasir_id = str(
            user.get("kasir_id")
            or user.get("id")
            or ""
        ).strip()
        kasir_nama = str(
            user.get("kasir_nama")
            or user.get("nama")
            or ""
        ).strip()
        cabang_id = self._as_positive_int(
            user.get("cabang_id"),
            self._as_positive_int(device_info.get("cabang_id"), 0),
        )
        dev_alias = str(
            user.get("dev_alias")
            or user.get("alias")
            or machine_id
            or "POS"
        ).strip()
        return {
            "kasir_id": kasir_id,
            "kasir_nama": kasir_nama,
            "dev_alias": dev_alias,
            "cabang_id": str(cabang_id) if cabang_id > 0 else "",
        }

    def _post_form(
        self,
        endpoint_config_key,
        payload,
        auth_required=True,
        timeout_override=None,
        trace_id="",
    ):
        endpoint_cfg = get_penjualan_endpoint_config()
        endpoint_name = PENJUALAN_ENDPOINT_KEYS.get(endpoint_config_key)
        if not endpoint_name:
            return self._error_payload(
                trace_id=trace_id,
                reason=f"unknown_endpoint_key:{endpoint_config_key}",
                error_code="PREORDER_UNKNOWN_ENDPOINT_KEY",
                message="Konfigurasi endpoint pre-order tidak ditemukan.",
            )
        url, url_error = build_endpoint_url(endpoint_name, endpoint_cfg=endpoint_cfg)
        if url_error:
            return self._error_payload(
                trace_id=trace_id,
                reason=str(url_error),
                error_code="PREORDER_ENDPOINT_NOT_READY",
                message="Endpoint pre-order belum siap.",
            )

        # edited by glg
        # Flow preload dialog berjalan di thread UI, jadi timeout dibatasi + tanpa retry
        # agar tidak terasa freeze saat endpoint down.
        timeout_default = max(1, min(int(get_request_timeout()), 3))
        timeout = float(timeout_override if timeout_override is not None else timeout_default)
        if timeout <= 0:
            timeout = float(timeout_default)
        try:
            response = self.request_with_retry(
                "POST",
                url,
                data=payload,
                timeout=timeout,
                retries=0,
                retry_on=(requests.RequestException,),
                auth_required=bool(auth_required),
            )
            data = parse_json_response(response, label=str(endpoint_name))
            if not isinstance(data, dict):
                return self._error_payload(
                    trace_id=trace_id,
                    reason="invalid_json",
                    error_code="PREORDER_INVALID_JSON",
                    message="Respons server tidak valid.",
                )
            try:
                status = int(data.get("status") or 0)
            except (TypeError, ValueError):
                status = 0
            if status != 1:
                return ErrorEnvelopeService.normalize_failure_payload(
                    data,
                    fallback_reason="api_reject",
                    fallback_error_code="PREORDER_API_REJECT",
                    trace_id=trace_id,
                    code_prefix="PREORDER",
                )
            if trace_id and not str(data.get("trace_id") or "").strip():
                data["trace_id"] = str(trace_id)
            return data
        except requests.exceptions.Timeout:
            return self._error_payload(
                trace_id=trace_id,
                reason="timeout",
                error_code="PREORDER_TIMEOUT",
                message="Request pre-order timeout.",
            )
        except requests.exceptions.ConnectionError:
            return self._error_payload(
                trace_id=trace_id,
                reason="connection_error",
                error_code="PREORDER_CONNECTION_ERROR",
                message="Koneksi ke server pre-order gagal.",
            )
        except requests.exceptions.HTTPError as exc:
            code = getattr(getattr(exc, "response", None), "status_code", "unknown")
            return self._error_payload(
                trace_id=trace_id,
                reason=f"http_error_{code}",
                error_code="PREORDER_HTTP_ERROR",
                message=f"Server merespons HTTP {code}.",
            )
        except (requests.RequestException, TypeError, ValueError, KeyError, AttributeError) as exc:
            return self._error_payload(
                trace_id=trace_id,
                reason=f"unexpected_error:{exc}",
                error_code="PREORDER_UNEXPECTED_ERROR",
                message="Terjadi kesalahan saat request pre-order.",
            )

    # edited by glg
    def get_preorder_list(self, user_info=None):
        trace_id = self._generate_trace_id("list")
        identity = self._resolve_request_identity(user_info)
        required_fields = ("kasir_id", "kasir_nama", "dev_alias", "cabang_id")
        missing = [field for field in required_fields if not str(identity.get(field) or "").strip()]
        if missing:
            return self._error_payload(
                trace_id=trace_id,
                reason=f"missing_required:{','.join(missing)}",
                error_code="PREORDER_MISSING_REQUIRED",
                message="Data identitas kasir belum lengkap.",
            )
        return self._post_form(
            "ep_preorder_get",
            payload=identity,
            auth_required=True,
            timeout_override=get_preorder_probe_timeout_sec(default=1),
            trace_id=trace_id,
        )

    # edited by glg
    def use_preorder(self, preorder_id, otp, user_info=None):
        trace_id = self._generate_trace_id("use")
        identity = self._resolve_request_identity(user_info)
        preorder_id_text = str(preorder_id or "").strip()
        otp_text = str(otp or "").strip()
        if not preorder_id_text or not otp_text:
            return self._error_payload(
                trace_id=trace_id,
                reason="missing_required:preorder_id,otp",
                error_code="PREORDER_MISSING_REQUIRED",
                message="Pre-order ID dan OTP wajib diisi.",
            )

        payload = {
            "preorder_id": preorder_id_text,
            "otp": otp_text,
            "kasir_id": identity.get("kasir_id", ""),
            "kasir_nama": identity.get("kasir_nama", ""),
            "dev_alias": identity.get("dev_alias", ""),
            "cabang_id": identity.get("cabang_id", ""),
        }
        required_fields = ("kasir_id", "kasir_nama", "dev_alias", "cabang_id")
        missing = [field for field in required_fields if not str(payload.get(field) or "").strip()]
        if missing:
            return self._error_payload(
                trace_id=trace_id,
                reason=f"missing_required:{','.join(missing)}",
                error_code="PREORDER_MISSING_REQUIRED",
                message="Data identitas kasir belum lengkap.",
            )

        return self._post_form(
            "ep_preorder_use",
            payload=payload,
            auth_required=True,
            trace_id=trace_id,
        )
