"""Tag management service for add/edit/delete operations (Phase 4).

Handles tag CRUD operations with validation per Spec Section 6.1.
"""

import time
from typing import Optional
from uuid import UUID, uuid4

import structlog
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from src.api.schemas.tags import TagStatus
from src.db.models import ExtractedRecord
from src.extraction_v2.tag_validator import TagValidator
from src.extraction_v2.taxonomy_loader import TaxonomyLoader

logger = structlog.get_logger(__name__)


class TagManagementService:
    """Service for managing tags (add/edit/delete).

    Phase 4 Enhancement: Implements tag management with validation per Spec Section 6.1.
    """

    def __init__(
        self,
        session: AsyncSession,
        taxonomy_loader: Optional[TaxonomyLoader] = None,
    ):
        """Initialize tag management service.

        Args:
            session: Database session
            taxonomy_loader: Optional taxonomy loader (creates default if None)
        """
        self.session = session
        self.taxonomy_loader = taxonomy_loader or TaxonomyLoader()
        self.validator = TagValidator(self.taxonomy_loader)
        self.logger = structlog.get_logger(__name__)

    async def add_tag(
        self,
        record_id: UUID,
        tag_name: str,
        user: str = "user",
        replace_tag_id: Optional[str] = None,
    ) -> tuple[bool, Optional[dict], Optional[list[str]]]:
        """Add or edit a tag on a record.

        Args:
            record_id: Record UUID
            tag_name: Tag name in format "namespace:value"
            user: User ID or identifier
            replace_tag_id: Optional tag ID to replace (for edit operation)

        Returns:
            Tuple of (success, tag_dict, validation_warnings)

        Note:
            - Validates tag before adding
            - If replace_tag_id provided, replaces existing tag
            - Auto-completes from pre-defined list (Spec Section 4.3.1)
        """
        # Validate tag
        is_valid, validation_status, reason = self.validator.validate_tag(tag_name)

        if not is_valid and validation_status == "rejected":
            return False, None, [f"Tag rejected: {reason}"]

        warnings = []
        if validation_status == "flagged":
            warnings.append(f"Unknown namespace flagged for review: {reason}")

        # Fetch record
        stmt = select(ExtractedRecord).where(ExtractedRecord.id == record_id)
        result = await self.session.execute(stmt)
        record = result.scalar_one_or_none()

        if not record:
            return False, None, ["Record not found"]

        tags = record.tags or []
        current_ts = int(time.time())

        # Check if replacing existing tag
        if replace_tag_id:
            tag_index = None
            for idx, tag in enumerate(tags):
                if tag.get("tag_id") == replace_tag_id:
                    tag_index = idx
                    break

            if tag_index is None:
                return False, None, ["Tag to replace not found"]

            # Update existing tag
            old_tag = tags[tag_index]
            tags[tag_index] = {
                "tag_id": replace_tag_id,  # Keep same ID
                "name": tag_name,
                "source": "human",
                "confidence": 1.0,  # Human edit = 100% confidence
                "status": self._determine_status_for_user_tag(tag_name),
                "history": old_tag.get("history", [])
                + [
                    {
                        "action": "edited",
                        "by": user,
                        "ts": current_ts,
                        "old_value": old_tag.get("name"),
                    }
                ],
            }

            self.logger.info(
                "tag_edited",
                record_id=str(record_id),
                tag_id=replace_tag_id,
                old_tag=old_tag.get("name"),
                new_tag=tag_name,
                user=user,
            )

        else:
            # Check for duplicate
            for existing_tag in tags:
                if existing_tag.get("name") == tag_name:
                    return False, None, ["Tag already exists on this record"]

            # Add new tag
            new_tag = {
                "tag_id": str(uuid4()),
                "name": tag_name,
                "source": "human",
                "confidence": 1.0,
                "status": self._determine_status_for_user_tag(tag_name),
                "history": [
                    {
                        "action": "suggested",
                        "by": user,
                        "ts": current_ts,
                    }
                ],
            }

            tags.append(new_tag)

            self.logger.info(
                "tag_added",
                record_id=str(record_id),
                tag_id=new_tag["tag_id"],
                tag_name=tag_name,
                user=user,
            )

        # Update record
        record.tags = tags
        await self.session.commit()

        # Return the new/updated tag
        target_tag = next(
            (
                t
                for t in tags
                if t.get("tag_id") == replace_tag_id
                or t.get("name") == tag_name
            ),
            None,
        )

        return True, target_tag, warnings if warnings else None

    async def delete_tag(
        self, record_id: UUID, tag_id: str, user: str = "user"
    ) -> tuple[bool, Optional[str]]:
        """Delete a tag from a record.

        Args:
            record_id: Record UUID
            tag_id: Tag UUID to delete
            user: User ID or identifier

        Returns:
            Tuple of (success, error_message)

        Note:
            Marks tag as deleted but preserves in history (soft delete).
        """
        # Fetch record
        stmt = select(ExtractedRecord).where(ExtractedRecord.id == record_id)
        result = await self.session.execute(stmt)
        record = result.scalar_one_or_none()

        if not record:
            return False, "record_not_found"

        tags = record.tags or []

        # Find tag
        tag_index = None
        for idx, tag in enumerate(tags):
            if tag.get("tag_id") == tag_id:
                tag_index = idx
                break

        if tag_index is None:
            return False, "tag_not_found"

        # Mark as deleted (soft delete)
        current_ts = int(time.time())
        tags[tag_index]["status"] = TagStatus.DELETED.value
        if "history" not in tags[tag_index]:
            tags[tag_index]["history"] = []
        tags[tag_index]["history"].append(
            {
                "action": "deleted",
                "by": user,
                "ts": current_ts,
            }
        )

        # Update record
        record.tags = tags
        await self.session.commit()

        self.logger.info(
            "tag_deleted",
            record_id=str(record_id),
            tag_id=tag_id,
            tag_name=tags[tag_index].get("name"),
            user=user,
        )

        return True, None

    def _determine_status_for_user_tag(self, tag_name: str) -> str:
        """Determine status for user-added tag.

        Args:
            tag_name: Tag name

        Returns:
            Status string ("verified" or "pending")

        Note:
            User-added pre-defined tags are auto-verified.
            User-added dynamic tags need admin review.
        """
        # Check if pre-defined
        is_predefined = tag_name in self.taxonomy_loader.get_all_tags()

        if is_predefined:
            return TagStatus.VERIFIED.value
        else:
            # Dynamic tags need review even if added by user
            return TagStatus.PENDING.value
