import configparser
from datetime import datetime, timezone
from typing import Optional
from os.path import dirname
from os import makedirs


class LatestStamps:
    """LatestStamps class.

    Convenience class for retrieving and storing data from the :option:`--latest-stamps` file.

    :param latest_stamps_file: path to file.

    .. versionadded:: 4.8"""
    PROFILE_ID = 'profile-id'
    PROFILE_PIC = 'profile-pic'
    POST_TIMESTAMP = 'post-timestamp'
    TAGGED_TIMESTAMP = 'tagged-timestamp'
    IGTV_TIMESTAMP = 'igtv-timestamp'
    STORY_TIMESTAMP = 'story-timestamp'
    ISO_FORMAT = '%Y-%m-%dT%H:%M:%S.%f%z'

    def __init__(self, latest_stamps_file):
        self.file = latest_stamps_file
        self.data = configparser.ConfigParser()
        self.data.read(latest_stamps_file)

    def _save(self):
        if dn := dirname(self.file):
            makedirs(dn, exist_ok=True)
        with open(self.file, 'w') as f:
            self.data.write(f)

    def _ensure_section(self, section: str):
        if not self.data.has_section(section):
            self.data.add_section(section)

    def get_profile_id(self, profile_name: str) -> Optional[int]:
        """Returns stored ID of profile."""
        try:
            return self.data.getint(profile_name, self.PROFILE_ID)
        except (configparser.Error, ValueError):
            return None

    def save_profile_id(self, profile_name: str, profile_id: int):
        """Stores ID of profile."""
        self._ensure_section(profile_name)
        self.data.set(profile_name, self.PROFILE_ID, str(profile_id))
        self._save()

    def rename_profile(self, old_profile: str, new_profile: str):
        """Renames a profile."""
        self._ensure_section(new_profile)
        for option in [self.PROFILE_ID, self.PROFILE_PIC, self.POST_TIMESTAMP,
                       self.TAGGED_TIMESTAMP, self.IGTV_TIMESTAMP, self.STORY_TIMESTAMP]:
            if self.data.has_option(old_profile, option):
                value = self.data.get(old_profile, option)
                self.data.set(new_profile, option, value)
        self.data.remove_section(old_profile)
        self._save()

    def _get_timestamp(self, section: str, key: str) -> datetime:
        try:
            return datetime.strptime(self.data.get(section, key), self.ISO_FORMAT)
        except (configparser.Error, ValueError):
            return datetime.fromtimestamp(0, timezone.utc)

    def _set_timestamp(self, section: str, key: str, timestamp: datetime):
        self._ensure_section(section)
        self.data.set(section, key, timestamp.strftime(self.ISO_FORMAT))
        self._save()

    def get_last_post_timestamp(self, profile_name: str) -> datetime:
        """Returns timestamp of last download of a profile's posts."""
        return self._get_timestamp(profile_name, self.POST_TIMESTAMP)

    def set_last_post_timestamp(self, profile_name: str, timestamp: datetime):
        """Sets timestamp of last download of a profile's posts."""
        self._set_timestamp(profile_name, self.POST_TIMESTAMP, timestamp)

    def get_last_tagged_timestamp(self, profile_name: str) -> datetime:
        """Returns timestamp of last download of a profile's tagged posts."""
        return self._get_timestamp(profile_name, self.TAGGED_TIMESTAMP)

    def set_last_tagged_timestamp(self, profile_name: str, timestamp: datetime):
        """Sets timestamp of last download of a profile's tagged posts."""
        self._set_timestamp(profile_name, self.TAGGED_TIMESTAMP, timestamp)

    def get_last_igtv_timestamp(self, profile_name: str) -> datetime:
        """Returns timestamp of last download of a profile's igtv posts."""
        return self._get_timestamp(profile_name, self.IGTV_TIMESTAMP)

    def set_last_igtv_timestamp(self, profile_name: str, timestamp: datetime):
        """Sets timestamp of last download of a profile's igtv posts."""
        self._set_timestamp(profile_name, self.IGTV_TIMESTAMP, timestamp)

    def get_last_story_timestamp(self, profile_name: str) -> datetime:
        """Returns timestamp of last download of a profile's stories."""
        return self._get_timestamp(profile_name, self.STORY_TIMESTAMP)

    def set_last_story_timestamp(self, profile_name: str, timestamp: datetime):
        """Sets timestamp of last download of a profile's stories."""
        self._set_timestamp(profile_name, self.STORY_TIMESTAMP, timestamp)

    def get_profile_pic(self, profile_name: str) -> str:
        """Returns filename of profile's last downloaded profile pic."""
        try:
            return self.data.get(profile_name, self.PROFILE_PIC)
        except configparser.Error:
            return ""

    def set_profile_pic(self, profile_name: str, profile_pic: str):
        """Sets filename of profile's last downloaded profile pic."""
        self._ensure_section(profile_name)
        self.data.set(profile_name, self.PROFILE_PIC, profile_pic)
        self._save()
