from dataclasses import dataclass
import logging
from pathlib import Path
from typing import Dict, List, Optional

import yaml
from physiq_cloud.time import Instant, Interval, TimeUnit
from pydantic import BaseModel, validator

from pojagi_dsp.series_frame import SftInfo
from pojagi_dsp.series_frame.generator.sampler import SftInterval

logger = logging.getLogger(__name__)


class ExcerptType(BaseModel):
    series_frame_type: str  # vci-vitalpatch-telemetry
    sft_interval: Optional[SftInterval]


class Excerpt(BaseModel):
    account: str  # uuid4
    id: str  # patient1
    interval: Interval  # "iso/iso"
    organization: str  # "maps"
    source_id: str  # "maps.physiq.io"
    types: List[ExcerptType]

    @validator("interval", pre=True)
    def timespan_to_interval(cls, timespan: str): return Interval(
        **{
            ["start", "end_exclusive"][idx]: Instant.parse_iso8601(stamp)
            for idx, stamp in enumerate(timespan.split("/"))
        }
    )


class ExtBundleConfig(BaseModel):
    excerpts: List[Excerpt]
    id: str  # clinical-event-trigger
    type: str = "PhysIQCloud"


@dataclass(frozen=True)
class BundleConfig:
    excerpts: Dict[str, Excerpt]
    id: str

    @staticmethod
    def create(bundle_dir: Path) -> "BundleConfig":
        yaml_files = (x.resolve() for x in bundle_dir.glob("**/*.yaml"))

        try:
            # the first yaml you encounter is BUNDLE_CONFIG.yaml
            ext_bundle_config = ExtBundleConfig.parse_obj(
                yaml.safe_load(next(yaml_files).read_text())
            )
        except StopIteration as si:
            raise RuntimeError(
                f"No yaml files found under \"{bundle_dir}\"."
            ) from si

        # the rest are INFO.yaml files
        info_files = list(yaml_files)

        for excerpt in ext_bundle_config.excerpts:
            logger.debug(f"Loading excerpt \"{excerpt.id}\".")

            for type_ in excerpt.types:
                logger.debug(f"Loading SFT \"{type_.series_frame_type}\".")
                # Make sure the info file belongs to this excerpt
                INFO = next(
                    x for x in info_files
                    if x.as_posix()
                        .split("/")[-3]
                        .startswith(excerpt.id)
                    if x.as_posix()
                        .split("/")[-2]
                        .startswith(type_.series_frame_type)
                )

                sft_info = SftInfo.parse_obj(
                    yaml.safe_load(INFO.read_text())
                )

                sft_info.alias = type_.series_frame_type

                type_.sft_interval = SftInterval(
                    info=sft_info,
                    interval=excerpt.interval,
                    frame_count=(
                        excerpt.interval
                        .to_duration()
                        .to_unix(TimeUnit.MICROSECONDS)
                        // sft_info.frame_size_micros
                    ),
                    files=sorted(INFO.parent.glob("**/*.sfhl")),
                )

        return BundleConfig(
            id=ext_bundle_config.id,
            excerpts={
                x.id: x
                for x in ext_bundle_config.excerpts
            },
        )
