"""
Storage interfaces for Upstox tokens.
"""

import json
import os
from abc import ABC, abstractmethod
from typing import Dict, Optional

from .exceptions import StorageError


class BaseStorage(ABC):
    """Abstract base class for token storage."""

    @abstractmethod
    def save_token(self, token_data: Dict) -> None:
        """Save token data dictionary."""
        pass

    @abstractmethod
    def get_token(self) -> Optional[Dict]:
        """Retrieve token data dictionary."""
        pass


class FileStorage(BaseStorage):
    """Stores token data in a local JSON file."""

    def __init__(self, file_path: str = "upstox_token.json"):
        self.file_path = file_path

    def save_token(self, token_data: Dict) -> None:
        try:
            # Add fetched_at timestamp for expiry checks (IST)
            import datetime

            import pytz
            ist = pytz.timezone("Asia/Kolkata")
            token_data["fetched_at"] = datetime.datetime.now(ist).isoformat()

            # Ensure parent directory exists
            parent_dir = os.path.dirname(os.path.abspath(self.file_path))
            if parent_dir:
                os.makedirs(parent_dir, exist_ok=True)

            with open(self.file_path, "w", encoding="utf-8") as f:
                json.dump(token_data, f, indent=4)
        except Exception as e:
            raise StorageError(f"Failed to save token to {self.file_path}: {e}")

    def get_token(self) -> Optional[Dict]:
        if not os.path.exists(self.file_path):
            return None
        try:
            with open(self.file_path, "r", encoding="utf-8") as f:
                return json.load(f)
        except Exception as e:
            raise StorageError(f"Failed to read token from {self.file_path}: {e}")


class MemoryStorage(BaseStorage):
    """Temporary in-memory storage (non-persistent)."""

    def __init__(self):
        self._data = None

    def save_token(self, token_data: Dict) -> None:
        import datetime

        import pytz
        ist = pytz.timezone("Asia/Kolkata")
        token_data["fetched_at"] = datetime.datetime.now(ist).isoformat()
        self._data = token_data

    def get_token(self) -> Optional[Dict]:
        return self._data
