import json
from datetime import date
from typing import (
    List,
    Optional,
)

from botocore.exceptions import ClientError

from ._DatalakeConfig import DatalakeConfig
from ._GoldOutboxOrderPictureService import GoldOutboxOrderPictureService


class GoldProcessedDaysRepository:
    def __init__(
        self,
        s3_client,
        datalake_config: DatalakeConfig,
        gold_outbox_service: GoldOutboxOrderPictureService,
    ):
        self.s3_client = s3_client
        self.datalake_config = datalake_config
        self.gold_outbox_service = gold_outbox_service

        self._cached_dict: Optional[dict] = None

    def get_active_store_codes(self) -> List[str]:
        if self._cached_dict is None:
            self._update_cache()

        from_state = set(self._cached_dict.keys())
        from_outbox = set(self.gold_outbox_service.list_active_store_codes_in_outbox())
        return sorted(from_state | from_outbox)

    def get_last_processed_day(self, store_code: str) -> Optional[date]:
        if self._cached_dict is None:
            self._update_cache()

        last_processed_str = self._cached_dict.get(store_code)
        if last_processed_str is None:
            return None

        return date.fromisoformat(last_processed_str)

    def set_last_processed_day(self, store_code: str, last_processed_day: date) -> None:
        if self._cached_dict is None:
            self._update_cache()

        self._cached_dict[store_code] = last_processed_day.isoformat()
        self.s3_client.put_object(
            Bucket=self.datalake_config.bucket_name,
            Key=self.datalake_config.last_processed_path,
            Body=json.dumps(self._cached_dict).encode(),
        )

    def _update_cache(self):
        try:
            response = self.s3_client.get_object(
                Bucket=self.datalake_config.bucket_name,
                Key=self.datalake_config.last_processed_path,
            )
            self._cached_dict = json.loads(response["Body"].read().decode())
        except ClientError as ex:
            if ex.response.get("Error", {}).get("Code") in ("NoSuchKey", "404"):
                self._cached_dict = {}
                return
            raise
