# NextGIS Connect
# Copyright (C) 2026  NextGIS
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or any
# later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, see <https://www.gnu.org/licenses/>.

from pathlib import Path
from typing import TYPE_CHECKING, Optional

from nextgis_connect.legacy.detached_editing.container.editing.commands.base import (
    DetachedLayerBaseCommand,
)
from nextgis_connect.legacy.detached_editing.utils import (
    AttachmentMetadata,
)
from nextgis_connect.platform.logging import logger
from nextgis_connect.platform.qgis.compat import QgsFeatureId, UndoCommand

if TYPE_CHECKING:
    from nextgis_connect.legacy.detached_editing.detached_layer import (
        DetachedLayer,
    )


class AttachmentAddCommand(DetachedLayerBaseCommand):
    """Command to create and manage an attachment addition in the edit buffer.

    This command stages an attachment file in managed storage for a given
    feature and file path. It supports undo/redo
    operations and is intended to be pushed to a vector layer QUndoStack.

    :ivar _attachment: Metadata object describing the created attachment.
    :vartype _attachment: AttachmentMetadata
    """

    _attachment: AttachmentMetadata

    def __init__(
        self,
        detached_layer: "DetachedLayer",
        feature_id: QgsFeatureId,
        file_path: Path,
    ) -> None:
        """Initialize the command and stage the attachment file.

        :param detached_layer: Detached layer the command will operate on.
        :type detached_layer: DetachedLayer
        :param feature_id: ID of the feature to attach the file to.
        :type feature_id: QgsFeatureId
        :param file_path: Path to the file being attached.
        :type file_path: Path
        """

        super().__init__(detached_layer)

        edit_buffer = self._detached_layer.edit_buffer
        self._attachment = edit_buffer._stage_new_attachment_file(
            feature_id, file_path
        )

    @property
    def attachment(self) -> AttachmentMetadata:
        """Return attachment metadata.

        :return: Attachment metadata.
        :rtype: AttachmentMetadata
        """

        return self._attachment

    def undo(self) -> None:
        """Revert the attachment addition.

        Revert the attachment creation performed by this command.
        """
        edit_buffer = self._detached_layer.edit_buffer

        edit_buffer._added_attachments[self._attachment.fid].pop(
            self._attachment.aid, None
        )

        edit_buffer.attachment_removed.emit(
            self._attachment.fid, self._attachment.aid
        )

        logger.debug(
            "Reverted attachment %s add command for feature %s",
            self._attachment.aid,
            self._attachment.fid,
        )

    def redo(self) -> None:
        """Apply the attachment addition.

        Perform the attachment creation performed by this command.
        """
        edit_buffer = self._detached_layer.edit_buffer

        edit_buffer._added_attachments[self._attachment.fid][
            self._attachment.aid
        ] = self._attachment

        edit_buffer.attachment_added.emit(
            self._attachment.fid, self._attachment.aid
        )

        logger.debug(
            "Added attachment %s command for feature %s",
            self._attachment.aid,
            self._attachment.fid,
        )

    def id(self) -> int:
        """Returns the ID of this command.

        A command ID is used in command compression.

        :return: Command ID.
        """
        return -1  # int(UndoCommandType.ATTACHMENT_REMOVE)

    def mergeWith(self, other: Optional[UndoCommand]) -> bool:
        """Attempts to merge this command with another command.

        :param other: The other command to merge with.
        :type other: Optional[UndoCommand]
        :return: True if the commands were merged, False otherwise.
        :rtype: bool
        """
        return False
