# This file is part of Gajim.
#
# SPDX-License-Identifier: GPL-3.0-only

from typing import cast

import time

from gi.repository import GLib
from gi.repository import Gtk

from gajim.common import app
from gajim.common.const import AvatarSize
from gajim.common.const import FTState
from gajim.common.i18n import _
from gajim.common.modules.httpupload import HTTPFileTransfer
from gajim.common.util.datetime import utc_now

from gajim.gtk.builder import get_builder
from gajim.gtk.conversation.rows.base import BaseRow
from gajim.gtk.conversation.rows.widgets import DateTimeLabel
from gajim.gtk.dialogs import ErrorDialog
from gajim.gtk.util import format_eta


class FileTransferRow(BaseRow):
    def __init__(self, account: str, transfer: HTTPFileTransfer) -> None:
        BaseRow.__init__(self, account)

        self.type = 'file-transfer'
        timestamp = utc_now()
        self.timestamp = timestamp.astimezone()
        self.db_timestamp = timestamp.timestamp()

        self._destroyed: bool = False

        if app.settings.get('use_kib_mib'):
            self._units = GLib.FormatSizeFlags.IEC_UNITS
        else:
            self._units = GLib.FormatSizeFlags.DEFAULT

        self._start_time = time.time()
        self._pulse = GLib.timeout_add(100, self._pulse_progressbar)

        self._transfer = transfer
        self._transfer.connect('state-changed', self._on_transfer_state_change)
        self._transfer.connect('progress', self._on_transfer_progress)

        avatar_placeholder = Gtk.Box()
        avatar_placeholder.set_size_request(AvatarSize.ROSTER, -1)
        self.grid.attach(avatar_placeholder, 0, 0, 1, 1)

        timestamp_widget = DateTimeLabel(self.timestamp)
        timestamp_widget.set_halign(Gtk.Align.START)
        timestamp_widget.set_valign(Gtk.Align.START)
        self.grid.attach(timestamp_widget, 1, 0, 1, 1)

        self._ui = get_builder('file_transfer.ui')
        self.grid.attach(self._ui.transfer_box, 1, 1, 1, 1)

        self._connect(self._ui.cancel_button, 'clicked', self._on_cancel_clicked)

        self._ui.file_name.set_text(transfer.filename)
        self._ui.transfer_description.set_text(
            transfer.get_state_description())

    def do_unroot(self) -> None:
        self._destroyed = True

        self._transfer.disconnect_all_from_obj(self)
        del self._transfer
        if self._pulse is not None:
            GLib.source_remove(self._pulse)

        BaseRow.do_unroot(self)

    def _on_cancel_clicked(self, _button: Gtk.Button) -> None:
        if self._transfer.state.is_active:
            self._transfer.cancel()

        cast(Gtk.ListBox, self.get_parent()).remove(self)

    def _on_transfer_state_change(self,
                                  transfer: HTTPFileTransfer,
                                  _signal_name: str,
                                  state: FTState) -> None:
        if self._destroyed:
            return

        if state.is_error:
            ErrorDialog(_('Error'),
                        transfer.error_text,
                        transient_for=app.window)
            cast(Gtk.ListBox, self.get_parent()).remove(self)

        if state.is_finished or state.is_cancelled:
            cast(Gtk.ListBox, self.get_parent()).remove(self)
            return

        description = transfer.get_state_description()
        if description:
            self._ui.transfer_description.set_text(description)

    def _pulse_progressbar(self):
        self._ui.progress_bar.pulse()
        return True

    def _on_transfer_progress(self,
                              transfer: HTTPFileTransfer,
                              _signal_name: str
                              ) -> None:
        if self._destroyed:
            return
        if self._pulse is not None:
            GLib.source_remove(self._pulse)
            self._pulse = None

        time_now = time.time()

        size_total = GLib.format_size_full(transfer.size, self._units)
        self._ui.file_size.set_text(size_total)

        progress = transfer.get_progress()
        seen = transfer.size * progress

        bytes_sec = int(round(seen / (time_now - self._start_time), 1))
        speed = f'{GLib.format_size_full(bytes_sec, self._units)}/s'
        self._ui.transfer_progress.set_tooltip_text(_('Speed: %s') % speed)

        if bytes_sec == 0:
            eta = '∞'
        else:
            eta = format_eta(round(
                (transfer.size - seen) / bytes_sec))

        self._ui.transfer_progress.set_text(
            _('%(progress)s %% (%(time)s remaining)') % {
                'progress': round(progress * 100),
                'time': eta})

        self._ui.progress_bar.set_fraction(progress)
