"""
Asset healing dialog for reconnecting missing images
"""

import os
import shutil
from typing import List, Dict, Set
from PyQt6.QtWidgets import (
    QDialog,
    QVBoxLayout,
    QHBoxLayout,
    QLabel,
    QPushButton,
    QListWidget,
    QListWidgetItem,
    QFileDialog,
    QGroupBox,
    QMessageBox,
)
from PyQt6.QtCore import Qt


class AssetHealDialog(QDialog):
    """Dialog for healing missing asset paths"""

    def __init__(self, project, parent=None):
        super().__init__(parent)
        self.project = project
        self.search_paths: List[str] = []
        self.missing_assets: Set[str] = set()

        self.setWindowTitle("Heal Missing Assets")
        self.resize(600, 500)

        self._init_ui()
        self._scan_missing_assets()

    def _init_ui(self):
        """Initialize the UI"""
        layout = QVBoxLayout()

        # Missing assets group
        missing_group = QGroupBox("Missing Assets")
        missing_layout = QVBoxLayout()

        self.missing_list = QListWidget()
        missing_layout.addWidget(self.missing_list)

        missing_group.setLayout(missing_layout)
        layout.addWidget(missing_group)

        # Search paths group
        search_group = QGroupBox("Search Paths")
        search_layout = QVBoxLayout()

        self.search_list = QListWidget()
        search_layout.addWidget(self.search_list)

        # Add/Remove buttons
        button_layout = QHBoxLayout()
        add_path_btn = QPushButton("Add Search Path...")
        add_path_btn.clicked.connect(self._add_search_path)
        button_layout.addWidget(add_path_btn)

        remove_path_btn = QPushButton("Remove Selected")
        remove_path_btn.clicked.connect(self._remove_search_path)
        button_layout.addWidget(remove_path_btn)

        search_layout.addLayout(button_layout)
        search_group.setLayout(search_layout)
        layout.addWidget(search_group)

        # Action buttons
        action_layout = QHBoxLayout()

        heal_btn = QPushButton("Attempt Healing")
        heal_btn.clicked.connect(self._attempt_healing)
        action_layout.addWidget(heal_btn)

        close_btn = QPushButton("Close")
        close_btn.clicked.connect(self.accept)
        action_layout.addWidget(close_btn)

        layout.addLayout(action_layout)

        self.setLayout(layout)

    def _scan_missing_assets(self):
        """Scan project for missing assets - only assets in project's assets folder are valid"""
        from pyPhotoAlbum.models import ImageData

        self.missing_assets.clear()
        self.missing_list.clear()

        # Check all pages for images that need healing
        # Images MUST be in the project's assets folder - absolute paths or external paths need healing
        for page in self.project.pages:
            for element in page.layout.elements:
                if isinstance(element, ImageData) and element.image_path:
                    needs_healing = False
                    reason = ""

                    # Absolute paths need healing (should be relative to assets/)
                    if os.path.isabs(element.image_path):
                        needs_healing = True
                        reason = "absolute path"
                    # Paths not starting with assets/ need healing
                    elif not element.image_path.startswith("assets/"):
                        needs_healing = True
                        reason = "not in assets folder"
                    else:
                        # Relative path in assets/ - check if file exists
                        full_path = os.path.join(self.project.folder_path, element.image_path)
                        if not os.path.exists(full_path):
                            needs_healing = True
                            reason = "file missing"

                    if needs_healing:
                        self.missing_assets.add(element.image_path)
                        print(f"Asset needs healing: {element.image_path} ({reason})")

        # Display missing assets
        if self.missing_assets:
            for asset in sorted(self.missing_assets):
                self.missing_list.addItem(asset)
        else:
            item = QListWidgetItem("No missing assets found!")
            item.setForeground(Qt.GlobalColor.darkGreen)
            self.missing_list.addItem(item)

    def _add_search_path(self):
        """Add a search path"""
        directory = QFileDialog.getExistingDirectory(
            self, "Select Search Path for Assets", "", QFileDialog.Option.ShowDirsOnly
        )

        if directory:
            if directory not in self.search_paths:
                self.search_paths.append(directory)
                self.search_list.addItem(directory)

    def _remove_search_path(self):
        """Remove selected search path"""
        current_row = self.search_list.currentRow()
        if current_row >= 0:
            self.search_paths.pop(current_row)
            self.search_list.takeItem(current_row)

    def _attempt_healing(self):
        """Attempt to heal missing assets by resolving stored paths and using search paths"""
        from pyPhotoAlbum.models import ImageData, set_asset_resolution_context

        healed_count = 0
        imported_count = 0
        still_missing = []

        # Update asset resolution context with search paths (for rendering after heal)
        set_asset_resolution_context(self.project.folder_path, self.search_paths)

        # Build mapping of missing paths to elements
        path_to_elements: Dict[str, List] = {}
        for page in self.project.pages:
            for element in page.layout.elements:
                if isinstance(element, ImageData) and element.image_path:
                    if element.image_path in self.missing_assets:
                        if element.image_path not in path_to_elements:
                            path_to_elements[element.image_path] = []
                        path_to_elements[element.image_path].append(element)

        # Try to find and import each missing asset
        for asset_path in self.missing_assets:
            found_path = None
            filename = os.path.basename(asset_path)

            # FIRST: Try to resolve the stored path directly from project folder
            # This handles paths like "../../home/user/Photos/image.jpg"
            if not os.path.isabs(asset_path):
                resolved = os.path.normpath(os.path.join(self.project.folder_path, asset_path))
                if os.path.exists(resolved):
                    found_path = resolved
                    print(f"Resolved relative path: {asset_path} → {resolved}")

            # SECOND: If it's an absolute path, check if it exists directly
            if not found_path and os.path.isabs(asset_path):
                if os.path.exists(asset_path):
                    found_path = asset_path
                    print(f"Found at absolute path: {asset_path}")

            # THIRD: Search in user-provided search paths
            if not found_path:
                for search_path in self.search_paths:
                    # Try direct match by filename
                    candidate = os.path.join(search_path, filename)
                    if os.path.exists(candidate):
                        found_path = candidate
                        break

                    # Try with same relative path structure
                    candidate = os.path.join(search_path, asset_path)
                    if os.path.exists(candidate):
                        found_path = candidate
                        break

            if found_path:
                healed_count += 1

                # Check if the found file needs to be imported
                # (i.e., it's not already in the assets folder)
                needs_import = True
                if not os.path.isabs(asset_path) and asset_path.startswith("assets/"):
                    # It's already a relative assets path, just missing from disk
                    # Copy it to the correct location
                    dest_path = os.path.join(self.project.folder_path, asset_path)
                    os.makedirs(os.path.dirname(dest_path), exist_ok=True)
                    shutil.copy2(found_path, dest_path)
                    print(f"Restored: {asset_path} from {found_path}")
                else:
                    # It's an absolute path or external path - need to import it
                    try:
                        new_asset_path = self.project.asset_manager.import_asset(found_path)
                        imported_count += 1

                        # Update all elements using this path
                        if asset_path in path_to_elements:
                            for element in path_to_elements[asset_path]:
                                element.image_path = new_asset_path

                        print(f"Imported and updated: {asset_path} → {new_asset_path}")
                    except Exception as e:
                        print(f"Error importing {found_path}: {e}")
                        still_missing.append(asset_path)
                        continue
            else:
                still_missing.append(asset_path)

        # Report results
        message = f"Healing complete!\n\n"
        message += f"Assets found: {healed_count}\n"
        if imported_count > 0:
            message += f"Assets imported to project: {imported_count}\n"
        message += f"Still missing: {len(still_missing)}"

        if still_missing:
            message += f"\n\nStill missing:\n"
            message += "\n".join(f"  - {asset}" for asset in still_missing[:10])
            if len(still_missing) > 10:
                message += f"\n  ... and {len(still_missing) - 10} more"

        QMessageBox.information(self, "Healing Results", message)

        # Reset asset resolution context to project folder only (no search paths for rendering)
        set_asset_resolution_context(self.project.folder_path)

        # Rescan to update the list
        self._scan_missing_assets()
