# -*- coding: utf-8 -*-
"""Gallery of daily Sentinel-2 previews for the selected date range."""

from qgis.PyQt.QtCore import Qt, QTimer, pyqtSignal
from qgis.PyQt.QtGui import QPixmap
from qgis.PyQt.QtWidgets import (
    QDialog,
    QFrame,
    QGridLayout,
    QHBoxLayout,
    QLabel,
    QProgressBar,
    QPushButton,
    QScrollArea,
    QSizePolicy,
    QVBoxLayout,
    QWidget,
)

from ..services.preview_loader import PreviewLoadWorker
from .dialog_theme import apply_dialog_theme

THUMB_SIZE = 260
CARD_SPACING = 14
CARD_PADDING = 10
# Cards are a fixed width so the number of columns can be computed exactly.
CARD_WIDTH = THUMB_SIZE + 2 * CARD_PADDING + 2


def _cloud_style(cloud):
    """Object name driving the colour of the cloud label."""
    if cloud is None:
        return 'previewCloudMid'
    if cloud < 20:
        return 'previewCloudLow'
    if cloud < 50:
        return 'previewCloudMid'
    return 'previewCloudHigh'


class SceneCard(QFrame):
    """One day: thumbnail, cloud cover and a shortcut to use that date."""

    use_requested = pyqtSignal(str)

    def __init__(self, scene, parent=None):
        super(SceneCard, self).__init__(parent)
        self.setObjectName('previewCard')
        self.setFixedWidth(CARD_WIDTH)
        self._day = scene.get('day', '')

        layout = QVBoxLayout(self)
        layout.setContentsMargins(
            CARD_PADDING, CARD_PADDING, CARD_PADDING, CARD_PADDING)
        layout.setSpacing(8)

        self.thumb = QLabel(u'Loading... / Đang tải...')
        self.thumb.setObjectName('previewThumb')
        self.thumb.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.thumb.setFixedSize(THUMB_SIZE, THUMB_SIZE)
        self.thumb.setWordWrap(True)
        layout.addWidget(self.thumb)

        day_label = QLabel(self._day)
        day_label.setObjectName('previewDay')
        layout.addWidget(day_label)

        cloud = scene.get('cloud')
        if cloud is None:
            cloud_text = u'Cloud n/a / Không có dữ liệu mây'
        else:
            cloud_text = u'Scene cloud ~{:.0f}% / Mây trong ảnh ~{:.0f}%'.format(
                cloud, cloud)
        cloud_label = QLabel(cloud_text)
        cloud_label.setObjectName(_cloud_style(cloud))
        cloud_label.setToolTip(
            u'Cloud cover reported for the scenes of that day, averaged. '
            u'The thumbnail shows the real situation over your area. / '
            u'Tỷ lệ mây trung bình của các cảnh ảnh ngày đó. '
            u'Ảnh xem trước mới thể hiện đúng tình trạng vùng của bạn.'
        )
        layout.addWidget(cloud_label)

        scenes = scene.get('scenes') or 0
        count_label = QLabel(u'{} scene(s) / {} cảnh'.format(scenes, scenes))
        count_label.setObjectName('mutedLabel')
        layout.addWidget(count_label)

        button_row = QHBoxLayout()
        use_button = QPushButton(u'Use this day / Chọn ngày này')
        use_button.setObjectName('useDayButton')
        use_button.clicked.connect(lambda: self.use_requested.emit(self._day))
        button_row.addWidget(use_button)
        button_row.addStretch(1)
        layout.addLayout(button_row)

    def set_thumbnail(self, data):
        pixmap = QPixmap()
        if not pixmap.loadFromData(data):
            self.set_message(u'Preview unavailable / Không xem được ảnh')
            return
        self.thumb.setPixmap(pixmap.scaled(
            THUMB_SIZE,
            THUMB_SIZE,
            Qt.AspectRatioMode.KeepAspectRatio,
            Qt.TransformationMode.SmoothTransformation,
        ))

    def set_message(self, message):
        self.thumb.setPixmap(QPixmap())
        self.thumb.setText(message)


class PreviewDialog(QDialog):
    """Shows one thumbnail per acquisition day so the user can judge clouds."""

    date_selected = pyqtSignal(str)

    def __init__(self, parent, geometry, start_date, end_date, area_name):
        super(PreviewDialog, self).__init__(parent)
        self.setWindowTitle(u'Daily previews / Xem ảnh theo ngày')
        self.setSizeGripEnabled(True)
        self.resize(980, 720)
        self.setMinimumSize(420, 420)
        apply_dialog_theme(self)

        self._cards = []
        self._columns = 0
        self._loader = None

        layout = QVBoxLayout(self)
        layout.setContentsMargins(16, 16, 16, 12)
        layout.setSpacing(10)

        header = QHBoxLayout()
        header.setSpacing(10)
        accent = QFrame()
        accent.setObjectName('accentBar')
        accent.setFixedWidth(4)
        header.addWidget(accent)

        title_column = QVBoxLayout()
        title_column.setSpacing(2)
        title = QLabel(u'Daily previews / Xem ảnh theo ngày')
        title.setObjectName('headerTitle')
        title_column.addWidget(title)
        subtitle = QLabel(u'{} — {} to {} / từ {} đến {}'.format(
            area_name, start_date, end_date, start_date, end_date,
        ))
        subtitle.setObjectName('subtitleLabel')
        subtitle.setWordWrap(True)
        title_column.addWidget(subtitle)
        header.addLayout(title_column, 1)
        layout.addLayout(header)

        self.status_label = QLabel(
            u'Searching acquisition dates... / Đang tìm các ngày có ảnh...'
        )
        self.status_label.setObjectName('loadStatusLabel')
        self.status_label.setWordWrap(True)
        layout.addWidget(self.status_label)

        self.progress = QProgressBar()
        self.progress.setRange(0, 0)
        self.progress.setTextVisible(False)
        layout.addWidget(self.progress)

        self.scroll = QScrollArea()
        self.scroll.setObjectName('previewScroll')
        self.scroll.setWidgetResizable(True)
        self.canvas = QWidget()
        self.canvas.setObjectName('previewCanvas')
        self.grid = QGridLayout(self.canvas)
        self.grid.setContentsMargins(CARD_SPACING, CARD_SPACING, CARD_SPACING, CARD_SPACING)
        self.grid.setSpacing(CARD_SPACING)
        self.grid.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.scroll.setWidget(self.canvas)
        layout.addWidget(self.scroll, 1)

        footer = QHBoxLayout()
        hint = QLabel(
            u'Previews keep the clouds and cover the rectangle around your area, '
            u'so pick a clearer day or narrow the range. / Ảnh xem trước giữ nguyên '
            u'mây và phủ hình chữ nhật quanh vùng của bạn, hãy chọn ngày ít mây hơn.'
        )
        hint.setObjectName('mutedLabel')
        hint.setWordWrap(True)
        footer.addWidget(hint, 1)
        close_button = QPushButton(u'Close / Đóng')
        close_button.clicked.connect(self.reject)
        footer.addWidget(close_button)
        layout.addLayout(footer)

        self._start_loader(geometry, start_date, end_date)

    def _start_loader(self, geometry, start_date, end_date):
        self._loader = PreviewLoadWorker(
            geometry, start_date, end_date, THUMB_SIZE, self,
        )
        self._loader.scenes_ready.connect(self._on_scenes_ready)
        self._loader.scenes_failed.connect(self._on_scenes_failed)
        self._loader.thumb_ready.connect(self._on_thumb_ready)
        self._loader.thumb_failed.connect(self._on_thumb_failed)
        self._loader.all_done.connect(self._on_all_done)
        self._loader.start()

    def _on_scenes_ready(self, scenes, truncated):
        if not scenes:
            self.progress.setVisible(False)
            self.status_label.setText(
                u'No Sentinel-2 acquisition in this range / '
                u'Không có ảnh Sentinel-2 trong khoảng này'
            )
            return

        for scene in scenes:
            card = SceneCard(scene, self.canvas)
            card.use_requested.connect(self._on_use_requested)
            card.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
            self._cards.append(card)
        self._columns = 0
        # Deferred so the scroll viewport already has its final width.
        QTimer.singleShot(0, self._relayout)

        message = u'{count} acquisition day(s) found, loading previews... / ' \
                  u'Tìm thấy {count} ngày có ảnh, đang tải ảnh xem trước...'.format(
                      count=len(scenes))
        if truncated:
            message += u' (showing the first {} / chỉ hiện {} ngày đầu)'.format(
                len(scenes), len(scenes))
        self.status_label.setText(message)
        self.progress.setRange(0, len(scenes))
        self.progress.setValue(0)

    def _relayout(self):
        """Reflow the cards so the gallery follows the dialog width."""
        if not self._cards:
            return
        available = self.scroll.viewport().width() - 2 * CARD_SPACING
        columns = int((available + CARD_SPACING) // (CARD_WIDTH + CARD_SPACING))
        columns = max(1, columns)
        if columns == self._columns:
            return

        self._columns = columns
        for card in self._cards:
            self.grid.removeWidget(card)
        for index, card in enumerate(self._cards):
            self.grid.addWidget(card, index // columns, index % columns)

    def resizeEvent(self, event):
        super(PreviewDialog, self).resizeEvent(event)
        self._relayout()

    def showEvent(self, event):
        super(PreviewDialog, self).showEvent(event)
        # Showing does not always resize, so the column count is refreshed here.
        self._relayout()

    def _on_scenes_failed(self, error_message):
        self.progress.setVisible(False)
        self.status_label.setText(
            u'Could not read the date list / Không đọc được danh sách ngày: {}'.format(
                error_message)
        )

    def _advance_progress(self):
        self.progress.setValue(self.progress.value() + 1)

    def _on_thumb_ready(self, index, data):
        if 0 <= index < len(self._cards):
            self._cards[index].set_thumbnail(data)
        self._advance_progress()

    def _on_thumb_failed(self, index, error_message):
        if 0 <= index < len(self._cards):
            self._cards[index].set_message(
                u'Preview failed / Không tải được ảnh'
            )
        self._advance_progress()

    def _on_all_done(self):
        self.progress.setVisible(False)
        self.status_label.setText(
            u'{count} day(s) ready — click "Use this day" to set that date. / '
            u'Đã tải {count} ngày — bấm "Chọn ngày này" để dùng ngày đó.'.format(
                count=len(self._cards))
        )

    def _on_use_requested(self, day):
        self.date_selected.emit(day)
        self.accept()

    def _stop_loader(self):
        if self._loader is not None and self._loader.isRunning():
            self._loader.requestInterruption()
            self._loader.wait(5000)

    def reject(self):
        self._stop_loader()
        super(PreviewDialog, self).reject()

    def accept(self):
        self._stop_loader()
        super(PreviewDialog, self).accept()

    def closeEvent(self, event):
        self._stop_loader()
        super(PreviewDialog, self).closeEvent(event)
