import json
import os
from typing import Any
from typing import Dict
from typing import List
from typing import Optional

from ...bliss_globals import current_session
from ...bliss_globals import setup_globals
from ...persistent.parameters import ParameterInfo
from ...processor import BlissScanType
from ...utils import directories
from ...xrpd.processor import XrpdProcessor
from .utils.pyfai_calib import DEFAULT_CALIB
from .utils.xrpd import lima_image_is_padded


class DemoXrpdProcessor(
    XrpdProcessor,
    parameters=[
        ParameterInfo("integration_options", category="PyFai"),
    ],
):
    def __init__(
        self,
        config: Optional[Dict[str, Any]] = None,
        defaults: Optional[Dict[str, Any]] = None,
        **deprecated_defaults: Dict[str, Any],
    ) -> None:
        defaults = self._merge_defaults(deprecated_defaults, defaults)
        defaults.setdefault(
            "integration_options",
            {
                "method": "no_csr_cython",
                "nbpt_rad": 4096,
                "unit": "q_nm^-1",
            },
        )

        super().__init__(config=config, defaults=defaults)
        self.queue = "celery"

    def get_integrate_inputs(
        self, scan, lima_name: str, task_identifier: str
    ) -> List[dict]:
        inputs = super().get_integrate_inputs(scan, lima_name, task_identifier)
        inputs.append(
            {
                "task_identifier": task_identifier,
                "name": "demo",
                "value": lima_image_is_padded(lima_name),
            }
        )
        return inputs

    def _get_demo_result_dir(self, dataset_filename: str) -> str:
        root_dir = directories.get_processed_dir(dataset_filename)
        return os.path.join(root_dir, "demo", "xrpd")

    def _get_workflows_dir(self, dataset_filename: str) -> str:
        root_dir = self._get_demo_result_dir(dataset_filename)
        return os.path.join(root_dir, "workflows")

    def _get_config_dir(self, dataset_filename: str) -> str:
        root_dir = self._get_demo_result_dir(dataset_filename)
        return os.path.join(root_dir, "config")

    def get_config_filename(self, lima_name: str) -> Optional[str]:
        root_dir = self._get_config_dir(current_session.scan_saving.filename)
        config_filename = os.path.join(root_dir, f"pyfaicalib_{lima_name}.json")

        if not os.path.exists(config_filename):
            os.makedirs(os.path.dirname(config_filename), exist_ok=True)

            poni = DEFAULT_CALIB[lima_name]
            if "detector_config" in poni:
                self.integration_options["version"] = 5

            with open(config_filename, "w") as f:
                json.dump(poni, f)

        return config_filename

    def get_integration_options(
        self, scan: BlissScanType, lima_name: str
    ) -> Optional[dict]:
        return self.integration_options.to_dict()

    def pct(self, *args, **kw):
        s = setup_globals.ct(*args, **kw)
        self.on_new_scan(s)
        return s

    def _expected_data_shapes_1d(self, lima_name: str, npoints: int):
        return {
            f"{lima_name}:q": (4096,),
            f"{lima_name}:intensity": (npoints, 4096),
            f"{lima_name}:points": (npoints,),
        }
