from datetime import datetime, timezone
from logging import Logger, getLogger
from typing import Any

log: Logger = getLogger(__name__)


class Page:
    def __init__(self, name: str,
                 ctime: float,
                 mtime: float,
                 html: str,
                 toc: str,
                 toc_tokens: list[str],
                 meta: dict[str, Any],
                 config: dict[str, Any],
                 dir_config: dict[str, Any]) -> None:
        log.debug('initializing a page object with name "%s"', name)
        # initial data
        self.name: str = name
        self.ctimestamp: float = ctime
        self.mtimestamp: float = mtime
        self.content: str = html
        self.toc: str = toc
        self.toc_tokens: list[str] = toc_tokens
        self.meta: dict[str, Any] = meta
        self.config: dict[str, Any] = config
        self.dir_config: dict[str, Any] = dir_config

        # data from self.meta
        self.title: str
        self.author: list[str]
        self.summary: str
        self.lang: str
        self.cdatetime: datetime
        self.mdatetime: datetime | None = None
        self.tags: list[tuple[str, str]] = []

        # constructed
        self.url: str
        self.cdate_rss: str
        self.cdate_sitemap: str
        self.mdate_rss: str | None = None
        self.mdate_sitemap: str | None = None

        self.next: Page | None = None
        self.previous: Page | None = None

    def __lt__(self, other):
        return self.ctimestamp < other.ctimestamp

    def __get_meta(self, var: str,
                   or_else: str | list[str] = ['']) -> str | list[str] | Any:
        if var in self.meta:
            log.debug('getting metadata "%s"', var)
            return self.meta[var]
        else:
            log.debug('getting metadata "%s" failed, using optional value "%s"',
                      var, or_else)
            return or_else

    # these date/cdate/mdate might be a bit overcomplicated

    def __date(self, dt: datetime, format: str) -> str:
        if format in self.config['fmt']:
            return dt.strftime(self.config['fmt'][format])
        else:
            log.warning('format "%s" not found in config, returning '
                        'empty string', format)
            return ''

    def cdate(self, format: str) -> str:
        return self.__date(self.cdatetime, format)

    def mdate(self, format: str) -> str:
        if self.mdatetime is None:
            log.warning('no mdatetime found, can\'t return a formatted string')
            return ''
        return self.__date(self.mdatetime, format)

    def from_timestamp(self, timestamp: float) -> datetime:
        return datetime.fromtimestamp(timestamp, tz=timezone.utc)

    # parses meta from self.meta
    def parse_metadata(self):
        log.debug('parsing metadata for file "%s"', self.name)
        self.title = str(self.__get_meta('title')[0])
        self.author = list(self.__get_meta('author'))
        self.summary = str(self.__get_meta('summary')[0])
        self.lang = str(self.__get_meta('lang', ['en'])[0])

        log.debug('parsing timestamp')
        self.cdatetime = self.from_timestamp(self.ctimestamp)
        self.cdate_rss = self.cdate('rss_date')
        self.cdate_sitemap = self.cdate('sitemap_date')

        if self.mtimestamp != 0.0:
            log.debug('parsing modified timestamp')
            self.mdatetime = self.from_timestamp(self.mtimestamp)
            self.mdate_rss = self.mdate('rss_date')
            self.mdate_sitemap = self.mdate('sitemap_date')
        else:
            log.debug('not parsing modified timestamp, hasn\'t been modified')

        if self.dir_config['tags']:
            log.debug('parsing tags')
            tags_only: list[str] = list(self.__get_meta('tags', []))
            if tags_only:
                tags_only.sort()

                for t in tags_only:
                    # need to specify dir_config['url'] as it is
                    #   a hardcoded tag url
                    tag_url: str = f'{self.dir_config["url"]}/tag/@{t}.html'
                    self.tags.append((t, tag_url))
            else:
                log.debug('no tags to parse')

        log.debug('parsing page url')
        # no need to specify dir_config['url'] as self.name already
        #   contains the relative url
        name_html: str = self.name.replace(".md", ".html")
        self.url = f'{self.config["url"]["main"]}/{name_html}'
        log.debug('final url "%s"', self.url)