"""Privatize people and associated data by determining if they are likely to be alive."""

from __future__ import annotations

from collections import defaultdict
from logging import getLogger

from typing_extensions import override

from betty.app.extension import UserFacingExtension
from betty.load import PostLoader
from betty.locale import Str
from betty.model.ancestry import Person, HasPrivacy
from betty.privatizer import Privatizer as PrivatizerApi
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from betty.model import Entity


class Privatizer(UserFacingExtension, PostLoader):
    """
    Extend the Betty Application with privatization features.
    """

    @override
    @classmethod
    def name(cls) -> str:
        return "betty.extension.Privatizer"

    @override
    async def post_load(self) -> None:
        self.privatize()

    @override
    @classmethod
    def label(cls) -> Str:
        return Str._("Privatizer")

    @override
    @classmethod
    def description(cls) -> Str:
        return Str._(
            "Determine if people can be proven to have died. If not, mark them and their associated entities private."
        )

    def privatize(self) -> None:
        """
        Privatize the project's ancestry.
        """
        logger = getLogger(__name__)
        logger.info(self._app.localizer._("Privatizing..."))

        privatizer = PrivatizerApi(
            self._app.project.configuration.lifetime_threshold,
            localizer=self._app.localizer,
        )

        newly_privatized: dict[type[HasPrivacy & Entity], int] = defaultdict(lambda: 0)
        entities: list[HasPrivacy & Entity] = []
        for entity in self._app.project.ancestry:
            if isinstance(entity, HasPrivacy):
                entities.append(entity)
                if entity.private:
                    newly_privatized[entity.type] -= 1  # type: ignore[index]

        for entity in entities:
            privatizer.privatize(entity)

        for entity in entities:
            if entity.private:
                newly_privatized[entity.type] += 1  # type: ignore[index]

        if newly_privatized[Person] > 0:
            logger.info(
                self._app.localizer._(
                    "Privatized {count} people because they are likely still alive."
                ).format(
                    count=str(newly_privatized[Person]),
                )
            )
        for entity_type in set(newly_privatized) - {Person}:
            if newly_privatized[entity_type] > 0:
                logger.info(
                    self._app.localizer._(
                        "Privatized {count} {entity_type}, because they are associated with private information."
                    ).format(
                        count=str(newly_privatized[entity_type]),
                        entity_type=entity_type.entity_type_label_plural().localize(
                            self._app.localizer
                        ),
                    )
                )
