# ui/result_window.py

import os
import cv2
import json
from PyQt5.QtWidgets import (
    QWidget, QVBoxLayout, QScrollArea, QHBoxLayout, QLabel,
    QLineEdit, QPushButton, QComboBox, QFileDialog, QSizePolicy, QLayout, QApplication, QMessageBox, QInputDialog
)
from PyQt5.QtGui import QPixmap, QImage, QIcon
from PyQt5.QtCore import Qt, QRect, QPoint, QSize
from config import t
from utils.csv_exporter import export_to_csv, CATEGORIES
from core.generator import MetadataGenerator
from utils.file_utils import slugify_filename
from datetime import datetime
from utils.path_utils import resource_path

def center_crop_pixmap_rect(pixmap, target_w, target_h):
    # Масштабируем так, чтобы короткая сторона >= целевого размера
    scaled = pixmap.scaled(
        target_w, target_h,
        Qt.KeepAspectRatioByExpanding,
        Qt.SmoothTransformation
    )
    # Проверяем границы!
    sw, sh = scaled.width(), scaled.height()
    x = max(0, (sw - target_w) // 2)
    y = max(0, (sh - target_h) // 2)
    # Делаем crop только если размеры позволяют
    w = min(target_w, sw)
    h = min(target_h, sh)
    cropped = scaled.copy(x, y, w, h)
    # Если вдруг картинка меньше, чем target — дорисовать рамку/заливку (опционально)
    return cropped

class FlowLayout(QLayout):
    def __init__(self, parent=None, margin=0, spacing=5):
        super().__init__(parent)
        self.setContentsMargins(margin, margin, margin, margin)
        self.setSpacing(spacing)
        self.itemList = []

    def addItem(self, item):
        self.itemList.append(item)

    def count(self):
        return len(self.itemList)

    def itemAt(self, index):
        return self.itemList[index] if 0 <= index < len(self.itemList) else None

    def takeAt(self, index):
        return self.itemList.pop(index) if 0 <= index < len(self.itemList) else None

    def expandingDirections(self):
        return Qt.Orientations(Qt.Horizontal)

    def hasHeightForWidth(self):
        return True

    def heightForWidth(self, width):
        return self._doLayout(QRect(0, 0, width, 0), True)

    def setGeometry(self, rect):
        super().setGeometry(rect)
        self._doLayout(rect, False)

    def sizeHint(self):
        return self.minimumSize()

    def minimumSize(self):
        size = QSize()
        for item in self.itemList:
            size = size.expandedTo(item.minimumSize())
        m = self.contentsMargins()
        return size + QSize(m.left() + m.right(), m.top() + m.bottom())

    def _doLayout(self, rect, testOnly):
        x, y, lineHeight = rect.x(), rect.y(), 0
        for item in self.itemList:
            widgetSize = item.sizeHint()
            spaceX, spaceY = self.spacing(), self.spacing()
            if x + widgetSize.width() > rect.right() and lineHeight > 0:
                x, y = rect.x(), y + lineHeight + spaceY
                lineHeight = 0
            if not testOnly:
                item.setGeometry(QRect(QPoint(x, y), widgetSize))
            x += widgetSize.width() + spaceX
            lineHeight = max(lineHeight, widgetSize.height())
        return y + lineHeight - rect.y()

class TagEditWidget(QWidget):
    def __init__(self, tags: list[str]):
        super().__init__()
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
        layout = FlowLayout(self)
        self.setLayout(layout)
        self.tags = []
        for tag in tags:
            self._add_tag(tag)
        self._add_input()

    def _add_tag(self, tag: str):
        if tag in self.tags:
            return
        frame = QWidget(self)
        frame.setStyleSheet("border-radius:4px; padding:4px; position: relative;")
        frame.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
        fl = QHBoxLayout(frame)
        fl.setContentsMargins(5, 2, 5, 2)
        fl.setSpacing(2)
        lbl, btn = QLabel(tag, frame), QPushButton("✕", frame)
        lbl.setStyleSheet("border: none;")
        btn.setFixedSize(16, 16)
        btn.setStyleSheet("QPushButton { border: none; background: transparent; } QPushButton:hover { color: red; }")
        btn.clicked.connect(lambda _, f=frame, tg=tag: self._remove_tag(f, tg))
        fl.addWidget(lbl)
        fl.addWidget(btn, alignment=Qt.AlignTop)
        self.layout().addWidget(frame)
        self.tags.append(tag)

    def _add_input(self):
        self.input = QLineEdit(self)
        self.input.setFixedHeight(24)
        self.input.setPlaceholderText(t("add_tag"))
        self.input.returnPressed.connect(self._on_enter)
        self.layout().addWidget(self.input)

    def _on_enter(self):
        txt = self.input.text().strip()
        if txt:
            self._add_tag(txt)
            self.input.clear()

    def _remove_tag(self, frame, tag):
        self.layout().removeWidget(frame)
        frame.deleteLater()
        if tag in self.tags:
            self.tags.remove(tag)

    def get_tags(self) -> list[str]:
        return list(self.tags)

    def set_tags(self, new_tags: list[str]):
        self.tags = []
        layout = self.layout()
        for i in reversed(range(layout.count() - 1)):
            item = layout.itemAt(i)
            widget = item.widget()
            if widget:
                layout.removeWidget(widget)
                widget.deleteLater()
        for tag in new_tags:
            self._add_tag(tag)

class ResultWindow(QWidget):
    def __init__(self, records: list[dict], title_len=100, desc_len=120, tags_len=50, platform="adobe"):
        super().__init__()
        self.setObjectName("ResultWindow")
        self.setWindowTitle(t("result_window_title"))
        self.resize(900, 850)
        self.title_len, self.desc_len, self.tags_len = title_len, desc_len, tags_len
        self.platform = platform

        self.items = []   # [(path, widget)]
        self.records = records.copy()  # делаем копию чтобы можно было изменять

        main_l = QVBoxLayout(self)
        scroll = QScrollArea(self)
        scroll.setWidgetResizable(True)
        container = QWidget()
        v = QVBoxLayout(container)
        v.setSpacing(10)
        v.setContentsMargins(5, 5, 5, 5)

        for rec in self.records:
            w = self._make_item(rec)
            v.addWidget(w)
            self.items.append((rec.get("path", rec["filename"]), w))

        container.setLayout(v)
        scroll.setWidget(container)
        main_l.addWidget(scroll)

        btn_l = QHBoxLayout()
        btn_l.addStretch()
        back = QPushButton(t("btn_back"), self)
        back.clicked.connect(self.go_back)
        save = QPushButton(t("btn_csv"), self)
        save.clicked.connect(self.save_csv)
        btn_l.addWidget(back)
        btn_l.addWidget(save)
        main_l.addLayout(btn_l)

    def _make_item(self, rec: dict) -> QWidget:
        w = QWidget()
        layout = QVBoxLayout(w)
        layout.setSpacing(5)
        layout.setContentsMargins(5, 5, 5, 5)
        path = rec.get("path", rec["filename"])

        # === ВЕРХНЯЯ ПОЛОСА: превью + крестик ===
        top_h = QHBoxLayout()
        preview = QLabel(w)
        preview.setAlignment(Qt.AlignCenter)
        MAX_W, MAX_H = 400, 220
        pixmap = None
        if os.path.exists(path):
            ext = os.path.splitext(path)[1].lower()
            if ext in ['.png', '.jpg', '.jpeg', '.bmp', '.webp', '.avif', '.gif']:
                pixmap = QPixmap(path)
            elif ext in ['.mp4', '.mov', '.avi']:
                cap = cv2.VideoCapture(path)
                ret, frame = cap.read()
                cap.release()
                if ret:
                    h, w_f, ch = frame.shape
                    img = QImage(frame.data, w_f, h, ch * w_f, QImage.Format_BGR888)
                    pixmap = QPixmap.fromImage(img)
        if pixmap:
            thumb = center_crop_pixmap_rect(pixmap, MAX_W, MAX_H)
            preview.setPixmap(thumb)
            preview.setFixedSize(MAX_W, MAX_H)
        else:
            preview.setText(t("no_preview"))
            preview.setFixedSize(MAX_W, MAX_H)
        top_h.addWidget(preview)
        top_h.addStretch()
        # Кнопка удаления (красный крестик)
        btn_del = QPushButton()
        btn_del.setIcon(QIcon(resource_path("assets/icons/close_red.png")))
        btn_del.setIconSize(QSize(22, 22))
        btn_del.setCursor(Qt.PointingHandCursor)
        btn_del.setStyleSheet("""
            QPushButton { border: none; background: transparent; }
            QPushButton:hover { background-color: rgba(255,0,0,30); border-radius: 4px; }
        """)
        btn_del.setToolTip(t("btn_remove_result") if t("btn_remove_result") != "btn_remove_result" else "Удалить результат")
        btn_del.clicked.connect(lambda _, wgt=w, path=path: self._remove_result(wgt, path))
        top_h.addWidget(btn_del)
        layout.addLayout(top_h)

        # ===== Заголовок (ЖИРНАЯ ПОДПИСЬ) =====
        lbl_title = QLabel(f"<b>{t('col_title')}</b>", w)
        layout.addWidget(lbl_title)
        # title input + кнопки
        hl_title = QHBoxLayout()
        title = QLineEdit(rec.get("title", ""), w)
        title.setObjectName("title")
        hl_title.addWidget(title)

        btn_copy_title = QPushButton(w)
        btn_copy_title.setIcon(QIcon(resource_path("assets/icons/copy.png")))
        btn_copy_title.setToolTip(t("tooltip_copy_title"))
        btn_copy_title.setFixedSize(24, 24)
        btn_copy_title.clicked.connect(lambda _, le=title: QApplication.clipboard().setText(le.text()))
        hl_title.addWidget(btn_copy_title)

        btn_rename = QPushButton(w)
        btn_rename.setIcon(QIcon(resource_path("assets/icons/edit.png")))
        btn_rename.setToolTip(t("tooltip_rename"))
        btn_rename.setFixedSize(24, 24)
        btn_rename.clicked.connect(lambda _, r=rec, widget=w: self.rename_file_by_title(r, widget))
        hl_title.addWidget(btn_rename)

        btn_regen = QPushButton(w)
        btn_regen.setIcon(QIcon(resource_path("assets/icons/refresh.png")))
        btn_regen.setToolTip(t("btn_regenerate"))
        btn_regen.setFixedSize(24, 24)
        btn_regen.clicked.connect(lambda _, p=path, widget=w: self.regenerate_metadata(p, widget))
        hl_title.addWidget(btn_regen)

        layout.addLayout(hl_title)

        # ===== Описание (ЖИРНАЯ ПОДПИСЬ) =====
        lbl_desc = QLabel(f"<b>{t('col_description')}</b>", w)
        layout.addWidget(lbl_desc)
        desc = QLineEdit(rec.get("description", ""), w)
        desc.setObjectName("description")
        desc.setPlaceholderText(t("col_description"))
        layout.addWidget(desc)

        # tags
        hl_tags = QHBoxLayout()
        tags = TagEditWidget(rec.get("keywords", []))
        tags.setObjectName("tags")
        hl_tags.addWidget(tags)
        btn_copy_tags = QPushButton(w)
        btn_copy_tags.setIcon(QIcon(resource_path("assets/icons/copy.png")))
        btn_copy_tags.setToolTip(t("tooltip_copy_tags"))
        btn_copy_tags.setFixedSize(24, 24)
        btn_copy_tags.clicked.connect(lambda _, tg=tags: QApplication.clipboard().setText(", ".join(tg.get_tags())))
        hl_tags.addWidget(btn_copy_tags)
        layout.addLayout(hl_tags)

        # category
        if self.platform == "adobe":
            combo = QComboBox(w)
            combo.addItems(CATEGORIES)
            cat = rec.get("category", "")
            if cat in CATEGORIES:
                combo.setCurrentText(cat)
            else:
                combo.addItem(cat)
                combo.setCurrentText(cat)
            combo.setObjectName("category")
            layout.addWidget(combo)

        return w

    def _remove_result(self, widget, path):
        idx = next((i for i, (p, w) in enumerate(self.items) if p == path and w == widget), None)
        if idx is not None:
            del self.records[idx]
            widget.setParent(None)
            del self.items[idx]

    def rename_file_by_title(self, rec, widget):
        title_edit = widget.findChild(QLineEdit, "title")
        title = title_edit.text().strip()
        old_path = rec.get("path", rec["filename"])
        ext = os.path.splitext(old_path)[1]
        dir_path = os.path.dirname(old_path)
        new_name = slugify_filename(title, ext)
        new_path = os.path.join(dir_path, new_name)
        if not title:
            QMessageBox.warning(self, t("error_title"), t("rename_empty_title"))
            return
        if os.path.abspath(old_path) == os.path.abspath(new_path):
            QMessageBox.information(self, t("info_title"), t("rename_same_name"))
            return
        if os.path.exists(new_path):
            QMessageBox.warning(self, t("error_title"), t("rename_exists"))
            return
        try:
            os.rename(old_path, new_path)
            rec["filename"] = new_name
            rec["path"] = new_path
            QMessageBox.information(self, t("success_title"), t("rename_success").format(old=os.path.basename(old_path), new=new_name))
        except Exception as e:
            QMessageBox.critical(self, t("error_title"), t("rename_error").format(error=e))

    def regenerate_metadata(self, path, widget):
        from api_clients.openai_client import get_openai_models
        from api_clients.gemini_client import get_gemini_models
        from api_clients.mistral_client import get_mistral_models
        from api_clients.deepseek_client import get_deepseek_models
        from api_clients.grok_client import get_grok_models
        from api_clients.openrouter_client import get_openrouter_models

        services = ["Gemini", "OpenAI", "Mistral", "DeepSeek", "Grok", "OpenRouter"]
        svc, ok = QInputDialog.getItem(
            self,
            t("dialog_choose_service"),
            t("dialog_choose_service_label"),
            services,
            editable=False
        )
        if not ok:
            return

        # Получаем список моделей для выбранного сервиса
        models_map = {
            "OpenAI": get_openai_models(),
            "Gemini": get_gemini_models(),
            "Mistral": get_mistral_models(),
            "DeepSeek": get_deepseek_models(),
            "Grok": get_grok_models(),
            "OpenRouter": get_openrouter_models(),
        }
        models = models_map.get(svc, {})
        model_key = None
        if models:
            model_names = list(models.keys())
            # Если моделей много, показываем диалог выбора
            if len(model_names) > 1:
                model_key, ok = QInputDialog.getItem(
                    self,
                    t("dialog_choose_service"),
                    t("dialog_choose_service_label"),
                    model_names,
                    editable=False
                )
                if not ok:
                    return
            else:
                model_key = model_names[0]

        try:
            gen = MetadataGenerator(svc, model=model_key)
            data = gen.generate(path, self.title_len, self.desc_len, self.tags_len)

            title = widget.findChild(QLineEdit, "title")
            desc = widget.findChild(QLineEdit, "description")
            tags = widget.findChild(TagEditWidget, "tags")
            cat = widget.findChild(QComboBox, "category")

            title.setText(data.get("title", ""))
            desc.setText(data.get("description", ""))
            tags.set_tags(data.get("keywords", []))

            if cat:
                cat.setCurrentText(data.get("category", ""))
        except Exception as e:
            QMessageBox.critical(self, t("error_title"), t("error_regenerate_failed").format(error=e))

    def go_back(self):
        from ui.main_window import MainWindow
        self.main = MainWindow()
        self.main.show()
        self.close()

    def save_csv(self):
        ts = datetime.now().strftime("meta_%d%m%Y%H%M.csv")
        path, _ = QFileDialog.getSaveFileName(self, t("save_csv_title"), ts, t("filter_csv"))
        if not path:
            return
        out = []
        for i, (file_path, widget) in enumerate(self.items):
            rec = self.records[i]
            title = widget.findChild(QLineEdit, "title").text()
            desc = widget.findChild(QLineEdit, "description").text()
            tags = widget.findChild(TagEditWidget, "tags").get_tags()
            combo = widget.findChild(QComboBox, "category")
            cat = combo.currentText() if combo else ""

            entry = {
                "filename": os.path.basename(file_path),
                "title": title,
                "description": desc,
                "keywords": tags
            }
            if self.platform == "adobe":
                entry["category"] = cat
            else:
                entry["category"] = ""
            out.append(entry)
        export_to_csv(out, path, platform=self.platform)
