from abc import ABC, abstractmethod
from typing import Optional

from iotas.note import Note, DirtyFields


class BackupStorage(ABC):
    """Backup storage interface."""

    @abstractmethod
    def add_note(self, note: Note) -> None:
        """Add a new note to the database.

        :param Note note: Note to add
        """
        raise NotImplementedError()

    @abstractmethod
    def get_all_notes_count(self, include_locally_deleted: bool = True) -> int:
        """Fetch the number of notes in the database.

        :param bool include_locally_deleted: Whether to include locally deleted notes in the count
        :return: The count
        :rtype: int
        """
        raise NotImplementedError()

    @abstractmethod
    def get_all_notes(self, load_content: bool = False) -> list[Note]:
        """Fetch all notes from the database.

        :param bool load_content: Whether to load the content for each note
        :return: List of notes
        :rtype: list[Note]
        """
        raise NotImplementedError()

    @abstractmethod
    def get_note_by_remote_id(self, remote_id: int) -> Optional[Note]:
        """Fetch note from the database by remote id.

        :param int remote_id: Remote id of the note
        :return: The note, or None
        :rtype: Optional[Note]
        """
        raise NotImplementedError()

    @abstractmethod
    def get_note_by_title(self, title: str) -> Optional[Note]:
        """Fetch note from the database by title.

        :param str title: Search title
        :return: The note, or None
        :rtype: Optional[Note]
        """
        raise NotImplementedError()

    @abstractmethod
    def persist_note_selective(self, note: Note, updated_fields: DirtyFields) -> None:
        """Persist local note based on remote changes.

        :param Note note: The note to update
        :param DirtyFields updated_fields: Which fields to update
        """
        raise NotImplementedError()

    @abstractmethod
    def create_duplicate_note(self, note: Note, reason: str) -> Note:
        """Create a duplicate note with a prefixed title.

        :param Note note: The note to duplicate
        :param str reason: The reason for the duplication, which is prefixed on the title
        """
        raise NotImplementedError()
