import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services.Compositor
import qs.Services.Hardware
import qs.Services.Keyboard
import qs.Services.Location
import qs.Services.Media
import qs.Widgets
import qs.Widgets.AudioSpectrum

Item {
  id: root
  anchors.fill: parent

  required property var lockControl
  required property var batteryIndicator
  required property var keyboardLayout
  required property TextInput passwordInput

  // Whether to enable lock screen animations (smooth cursor blink).
  // Defaults to false to reduce GPU usage.  Set Settings.data.general.lockScreenAnimations = true to restore.
  readonly property bool animationsEnabled: Settings.data.general.lockScreenAnimations || false

  Component.onCompleted: {
    if (Settings.data.general.autoStartAuth) {
      doUnlock();
    }
  }

  function doUnlock() {
    if (lockControl) {
      lockControl.tryUnlock();
    }
  }

  // Timer properties
  readonly property int timerDuration: Settings.data.general.lockScreenCountdownDuration
  property string pendingAction: ""
  property bool timerActive: false
  property int timeRemaining: 0
  readonly property bool weatherReady: Settings.data.location.weatherEnabled && (LocationService.data.weather !== null)

  // Timer management functions
  function startTimer(action) {
    // Check if global countdown is disabled
    if (!Settings.data.general.enableLockScreenCountdown) {
      executeAction(action);
      return;
    }

    if (timerActive && pendingAction === action) {
      // Second click - execute immediately
      executeAction(action);
      return;
    }

    pendingAction = action;
    timeRemaining = timerDuration;
    timerActive = true;
    countdownTimer.start();
  }

  function cancelTimer() {
    timerActive = false;
    pendingAction = "";
    timeRemaining = 0;
    countdownTimer.stop();
  }

  function executeAction(action) {
    // Stop timer but don't reset other properties yet
    countdownTimer.stop();

    // Execute the action
    switch (action) {
    case "logout":
      CompositorService.logout();
      break;
    case "suspend":
      CompositorService.suspend();
      break;
    case "hibernate":
      CompositorService.hibernate();
      break;
    case "reboot":
      CompositorService.reboot();
      break;
    case "userspaceReboot":
      CompositorService.userspaceReboot();
      break;
    case "shutdown":
      CompositorService.shutdown();
      break;
    }

    // Reset timer state
    cancelTimer();
  }

  // Countdown timer
  Timer {
    id: countdownTimer
    interval: 100
    repeat: true
    onTriggered: {
      timeRemaining -= interval;
      if (timeRemaining <= 0) {
        executeAction(pendingAction);
      }
    }
  }

  // Compact status indicators container (compact mode only)
  Rectangle {
    width: {
      var hasBattery = batteryIndicator.isReady;
      var hasKeyboard = keyboardLayout.currentLayout !== "Unknown";
      var hasCaps = LockKeysService.capsLockOn;
      var hasCapsSlot = hasBattery || hasKeyboard || hasCaps;

      var visibleCount = 0;
      if (hasBattery)
        visibleCount++;
      if (hasKeyboard)
        visibleCount++;
      if (hasCapsSlot)
        visibleCount++;

      if (visibleCount >= 3) {
        return 280;
      } else if (visibleCount === 2) {
        return 200;
      } else if (visibleCount === 1) {
        return 120;
      } else {
        return 0;
      }
    }
    height: 40
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.bottom: parent.bottom
    anchors.bottomMargin: 96 + (Settings.data.general.compactLockScreen ? 116 : 220)
    topLeftRadius: Style.radiusL
    topRightRadius: Style.radiusL
    color: Color.mSurface
    visible: Settings.data.general.compactLockScreen && (batteryIndicator.isReady || keyboardLayout.currentLayout !== "Unknown" || LockKeysService.capsLockOn)

    RowLayout {
      id: compactStatusRow
      anchors.centerIn: parent
      spacing: Style.marginL

      // Battery indicator
      RowLayout {
        spacing: Style.marginS
        visible: batteryIndicator.isReady

        NIcon {
          icon: batteryIndicator.icon
          pointSize: Style.fontSizeM
          color: batteryIndicator.charging ? Color.mPrimary : Color.mOnSurfaceVariant
        }

        NText {
          text: Math.round(batteryIndicator.percent) + "%"
          color: Color.mOnSurfaceVariant
          pointSize: Style.fontSizeM
        }
      }

      // Keyboard layout indicator
      RowLayout {
        spacing: 6
        visible: keyboardLayout.currentLayout !== "Unknown"

        NIcon {
          icon: "keyboard"
          pointSize: Style.fontSizeM
          color: Color.mOnSurfaceVariant
        }

        NText {
          text: keyboardLayout.currentLayout
          color: Color.mOnSurfaceVariant
          pointSize: Style.fontSizeM
          elide: Text.ElideRight
        }
      }

      // Caps Lock indicator
      RowLayout {
        spacing: 6
        visible: batteryIndicator.isReady || keyboardLayout.currentLayout !== "Unknown" || LockKeysService.capsLockOn

        NIcon {
          icon: "lock"
          pointSize: Style.fontSizeM
          color: LockKeysService.capsLockOn ? Color.mPrimary : Qt.alpha(Color.mOnSurfaceVariant, 0.5)
        }

        NText {
          text: I18n.tr("bar.lock-keys.show-caps-lock-label")
          color: LockKeysService.capsLockOn ? Color.mOnSurfaceVariant : Qt.alpha(Color.mOnSurfaceVariant, 0.65)
          pointSize: Style.fontSizeM
          elide: Text.ElideRight
        }
      }
    }
  }

  // Bottom container with weather, password input and controls
  Rectangle {
    id: bottomContainer

    // Support for removing the session/power buttons at the bottom.
    readonly property int deltaY: Settings.data.general.showSessionButtonsOnLockScreen ? 0 : (Settings.data.general.compactLockScreen ? 36 : 48) + 14

    height: {
      let calcHeight = Settings.data.general.compactLockScreen ? 120 : 220;
      if (!Settings.data.general.showSessionButtonsOnLockScreen) {
        calcHeight -= bottomContainer.deltaY;
      }
      return calcHeight;
    }
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.bottom: parent.bottom
    anchors.bottomMargin: 100 + bottomContainer.deltaY
    radius: Style.radiusL
    color: Color.mSurface

    width: Settings.data.general.showHibernateOnLockScreen ? 860 : 810

    ColumnLayout {
      anchors.fill: parent
      anchors.margins: 14
      spacing: Style.marginL

      // Top info row
      RowLayout {
        Layout.fillWidth: true
        Layout.preferredHeight: 65
        spacing: Style.marginXL
        visible: !Settings.data.general.compactLockScreen

        // Media widget with visualizer
        Item {
          Layout.preferredWidth: Style.marginM
          visible: MediaService.currentPlayer && MediaService.canPlay
        }

        Rectangle {
          Layout.preferredWidth: 220
          // Expand to take remaining space when weather is hidden
          Layout.fillWidth: !(Settings.data.location.weatherEnabled && LocationService.data.weather !== null)
          Layout.preferredHeight: 50
          radius: Style.radiusL
          color: "transparent"
          clip: true
          visible: MediaService.currentPlayer && MediaService.canPlay

          Loader {
            anchors.fill: parent
            anchors.margins: 4
            active: Settings.data.audio.visualizerType === "linear"
            z: 0
            sourceComponent: NLinearSpectrum {
              anchors.fill: parent
              values: SpectrumService.values
              fillColor: Color.mPrimary
              opacity: 0.4
              mirrored: Settings.data.audio.spectrumMirrored
            }
          }

          Loader {
            anchors.fill: parent
            anchors.margins: 4
            active: Settings.data.audio.visualizerType === "mirrored"
            z: 0
            sourceComponent: NMirroredSpectrum {
              anchors.fill: parent
              values: SpectrumService.values
              fillColor: Color.mPrimary
              opacity: 0.4
              mirrored: Settings.data.audio.spectrumMirrored
            }
          }

          Loader {
            anchors.fill: parent
            anchors.margins: 4
            active: Settings.data.audio.visualizerType === "wave"
            z: 0
            sourceComponent: NWaveSpectrum {
              anchors.fill: parent
              values: SpectrumService.values
              fillColor: Color.mPrimary
              opacity: 0.4
              mirrored: Settings.data.audio.spectrumMirrored
            }
          }

          RowLayout {
            anchors.fill: parent
            anchors.margins: 8
            spacing: Style.marginM
            z: 1

            Rectangle {
              Layout.preferredWidth: 34
              Layout.preferredHeight: 34
              radius: Math.min(Style.radiusL, width / 2)
              color: "transparent"
              clip: true

              NImageRounded {
                anchors.fill: parent
                anchors.margins: 2
                radius: Math.min(Style.radiusL, width / 2)
                imagePath: MediaService.trackArtUrl
                fallbackIcon: "disc"
                fallbackIconSize: Style.fontSizeM
                borderColor: Color.mOutline
                borderWidth: Style.borderS
              }
            }

            ColumnLayout {
              Layout.fillWidth: true
              spacing: Style.marginXXS

              NText {
                text: MediaService.trackTitle || "No media"
                pointSize: Style.fontSizeM
                color: Color.mOnSurface
                Layout.fillWidth: true
                elide: Text.ElideRight
              }

              NText {
                text: MediaService.trackArtist || ""
                pointSize: Style.fontSizeM
                color: Color.mOnSurfaceVariant
                Layout.fillWidth: true
                elide: Text.ElideRight
              }
            }

            // Media controls (when enabled)
            RowLayout {
              spacing: Style.marginXS
              visible: Settings.data.general.enableLockScreenMediaControls
              Layout.alignment: Qt.AlignHCenter

              Rectangle {
                width: 28
                height: 28
                radius: Math.min(Style.radiusL, width / 2)
                color: prevButtonArea.containsMouse ? Color.mPrimary : Qt.alpha(Color.mOnSurface, 0.1)
                visible: MediaService.canGoPrevious

                NIcon {
                  anchors.centerIn: parent
                  icon: "media-prev"
                  pointSize: Style.fontSizeM
                  color: prevButtonArea.containsMouse ? Color.mOnPrimary : Color.mOnSurface

                  Behavior on color {
                    ColorAnimation {
                      duration: Style.animationFast
                      easing.type: Easing.OutCubic
                    }
                  }
                }

                MouseArea {
                  id: prevButtonArea
                  anchors.fill: parent
                  hoverEnabled: true
                  cursorShape: Qt.PointingHandCursor
                  onClicked: MediaService.canGoPrevious ? MediaService.previous() : {}
                }

                Behavior on color {
                  ColorAnimation {
                    duration: Style.animationFast
                    easing.type: Easing.OutCubic
                  }
                }
              }

              Rectangle {
                width: 32
                height: 32
                radius: Math.min(Style.radiusL, width / 2)
                color: playPauseButtonArea.containsMouse ? Color.mPrimary : Qt.alpha(Color.mOnSurface, 0.15)
                visible: MediaService.canPlay || MediaService.canPause

                NIcon {
                  anchors.centerIn: parent
                  icon: MediaService.isPlaying ? "media-pause" : "media-play"
                  pointSize: Style.fontSizeL
                  color: playPauseButtonArea.containsMouse ? Color.mOnPrimary : Color.mOnSurface

                  Behavior on color {
                    ColorAnimation {
                      duration: Style.animationFast
                      easing.type: Easing.OutCubic
                    }
                  }
                }

                MouseArea {
                  id: playPauseButtonArea
                  anchors.fill: parent
                  hoverEnabled: true
                  cursorShape: Qt.PointingHandCursor
                  onClicked: (MediaService.canPlay || MediaService.canPause) ? MediaService.playPause() : {}
                }

                Behavior on color {
                  ColorAnimation {
                    duration: Style.animationFast
                    easing.type: Easing.OutCubic
                  }
                }
              }

              Rectangle {
                width: 28
                height: 28
                radius: Math.min(Style.radiusL, width / 2)
                color: nextButtonArea.containsMouse ? Color.mPrimary : Qt.alpha(Color.mOnSurface, 0.1)
                visible: MediaService.canGoNext

                NIcon {
                  anchors.centerIn: parent
                  icon: "media-next"
                  pointSize: Style.fontSizeM
                  color: nextButtonArea.containsMouse ? Color.mOnPrimary : Color.mOnSurface

                  Behavior on color {
                    ColorAnimation {
                      duration: Style.animationFast
                      easing.type: Easing.OutCubic
                    }
                  }
                }

                MouseArea {
                  id: nextButtonArea
                  anchors.fill: parent
                  hoverEnabled: true
                  cursorShape: Qt.PointingHandCursor
                  onClicked: MediaService.canGoNext ? MediaService.next() : {}
                }

                Behavior on color {
                  ColorAnimation {
                    duration: Style.animationFast
                    easing.type: Easing.OutCubic
                  }
                }
              }
            }
          }
        }

        Rectangle {
          Layout.preferredWidth: 1
          Layout.fillHeight: true
          Layout.rightMargin: 4
          color: Qt.alpha(Color.mOutline, 0.3)
          visible: MediaService.currentPlayer && MediaService.canPlay
        }

        Item {
          Layout.preferredWidth: Style.marginM
          visible: !(MediaService.currentPlayer && MediaService.canPlay)
        }

        // Current weather
        RowLayout {
          visible: Settings.data.location.weatherEnabled && LocationService.data.weather !== null
          Layout.preferredWidth: 180
          spacing: Style.marginM

          Item {
            Layout.preferredWidth: lockMainWeatherIconSide
            Layout.preferredHeight: lockMainWeatherIconSide
            Layout.alignment: Qt.AlignVCenter
            readonly property int lockMainWeatherIconSide: Math.round(Style.fontSizeXXXL * Style.uiScaleRatio * 1.6)

            NIcon {
              visible: !LocationService.taliaWeatherMascotActive || !weatherReady
              anchors.centerIn: parent
              icon: weatherReady ? LocationService.weatherSymbolFromCode(LocationService.data.weather.current_weather.weathercode) : "weather-cloud-off"
              pointSize: Style.fontSizeXXXL
              color: Color.mPrimary
            }
            Loader {
              active: LocationService.taliaWeatherMascotActive && weatherReady
              anchors.fill: parent
              asynchronous: true
              sourceComponent: Component {
                Image {
                  anchors.fill: parent
                  fillMode: Image.PreserveAspectFit
                  smooth: true
                  mipmap: true
                  asynchronous: true
                  source: Qt.resolvedUrl(LocationService.taliaWeatherImageFromCode(LocationService.data.weather.current_weather.weathercode))
                }
              }
            }
          }

          ColumnLayout {
            Layout.fillWidth: true
            spacing: Style.marginXXS

            RowLayout {
              Layout.fillWidth: true
              spacing: Style.marginL

              NText {
                text: {
                  var temp = LocationService.data.weather.current_weather.temperature;
                  var suffix = "C";
                  if (Settings.data.location.useFahrenheit) {
                    temp = LocationService.celsiusToFahrenheit(temp);
                    suffix = "F";
                  }
                  temp = Math.round(temp);
                  return temp + "°" + suffix;
                }
                pointSize: Style.fontSizeXL
                font.weight: Style.fontWeightBold
                color: Color.mOnSurface
              }

              NText {
                text: {
                  var wind = LocationService.data.weather.current_weather.windspeed;
                  var unit = "km/h";
                  if (Settings.data.location.useFahrenheit) {
                    wind = wind * 0.621371; // Convert km/h to mph
                    unit = "mph";
                  }
                  wind = Math.round(wind);
                  return wind + " " + unit;
                }
                pointSize: Style.fontSizeM
                color: Color.mOnSurfaceVariant
              }
            }

            RowLayout {
              Layout.fillWidth: true
              spacing: Style.marginM

              NText {
                text: Settings.data.location.name.split(",")[0]
                pointSize: Style.fontSizeM
                color: Color.mOnSurfaceVariant
                visible: !Settings.data.location.hideWeatherCityName
              }

              NText {
                text: (LocationService.data.weather.current && LocationService.data.weather.current.relativehumidity_2m) ? LocationService.data.weather.current.relativehumidity_2m + "% humidity" : ""
                pointSize: Style.fontSizeM
                color: Color.mOnSurfaceVariant
              }
            }
          }
        }

        // Forecast
        RowLayout {
          visible: Settings.data.location.weatherEnabled && LocationService.data.weather !== null
          Layout.preferredWidth: 260
          Layout.rightMargin: 8
          spacing: Style.marginXS

          Repeater {
            model: MediaService.currentPlayer && MediaService.canPlay ? 2 : 4
            delegate: ColumnLayout {
              Layout.fillWidth: true
              spacing: Style.marginXXS + 1

              NText {
                text: {
                  var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"));
                  return I18n.locale.toString(weatherDate, "ddd");
                }
                pointSize: Style.fontSizeM
                color: Color.mOnSurfaceVariant
                horizontalAlignment: Text.AlignHCenter
                Layout.fillWidth: true
              }

              Item {
                Layout.preferredWidth: lockForecastWeatherIconSide
                Layout.preferredHeight: lockForecastWeatherIconSide
                Layout.alignment: Qt.AlignHCenter
                readonly property int lockForecastWeatherIconSide: Math.round(Style.fontSizeXL * Style.uiScaleRatio * 1.6)

                NIcon {
                  visible: !LocationService.taliaWeatherMascotActive
                  anchors.centerIn: parent
                  icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index])
                  pointSize: Style.fontSizeXL
                  color: Color.mOnSurfaceVariant
                }
                Loader {
                  active: LocationService.taliaWeatherMascotActive
                  anchors.fill: parent
                  asynchronous: true
                  sourceComponent: Component {
                    Image {
                      anchors.fill: parent
                      fillMode: Image.PreserveAspectFit
                      smooth: true
                      mipmap: true
                      asynchronous: true
                      source: Qt.resolvedUrl(LocationService.taliaWeatherImageFromCode(LocationService.data.weather.daily.weathercode[index]))
                    }
                  }
                }
              }

              NText {
                text: {
                  var max = LocationService.data.weather.daily.temperature_2m_max[index];
                  var min = LocationService.data.weather.daily.temperature_2m_min[index];
                  if (Settings.data.location.useFahrenheit) {
                    max = LocationService.celsiusToFahrenheit(max);
                    min = LocationService.celsiusToFahrenheit(min);
                  }
                  max = Math.round(max);
                  min = Math.round(min);
                  return max + "°/" + min + "°";
                }
                pointSize: Style.fontSizeM
                font.weight: Style.fontWeightMedium
                color: Color.mOnSurfaceVariant
                horizontalAlignment: Text.AlignHCenter
                Layout.fillWidth: true
              }
            }
          }
        }

        Item {
          Layout.fillWidth: batteryIndicator.isReady
        }

        // Battery and Keyboard Layout (full mode only)
        ColumnLayout {
          Layout.alignment: (batteryIndicator.isReady) ? (Qt.AlignRight | Qt.AlignVCenter) : Qt.AlignVCenter
          spacing: Style.marginM
          visible: batteryIndicator.isReady || keyboardLayout.currentLayout !== "Unknown" || LockKeysService.capsLockOn

          // Battery
          RowLayout {
            spacing: Style.marginXS
            visible: batteryIndicator.isReady

            NIcon {
              icon: batteryIndicator.icon
              pointSize: Style.fontSizeM
              color: batteryIndicator.charging ? Color.mPrimary : Color.mOnSurfaceVariant
            }

            NText {
              text: Math.round(batteryIndicator.percent) + "%"
              color: Color.mOnSurfaceVariant
              pointSize: Style.fontSizeM
            }
          }

          // Keyboard Layout
          RowLayout {
            spacing: Style.marginXS
            visible: keyboardLayout.currentLayout !== "Unknown"

            NIcon {
              icon: "keyboard"
              pointSize: Style.fontSizeM
              color: Color.mOnSurfaceVariant
            }

            NText {
              text: keyboardLayout.currentLayout
              color: Color.mOnSurfaceVariant
              pointSize: Style.fontSizeM
              elide: Text.ElideRight
            }
          }

          // Caps Lock
          RowLayout {
            spacing: Style.marginXS
            visible: batteryIndicator.isReady || keyboardLayout.currentLayout !== "Unknown" || LockKeysService.capsLockOn

            NIcon {
              icon: "lock"
              pointSize: Style.fontSizeM
              color: LockKeysService.capsLockOn ? Color.mPrimary : Qt.alpha(Color.mOnSurfaceVariant, 0.5)
            }

            NText {
              text: I18n.tr("bar.lock-keys.show-caps-lock-label")
              color: LockKeysService.capsLockOn ? Color.mOnSurfaceVariant : Qt.alpha(Color.mOnSurfaceVariant, 0.65)
              pointSize: Style.fontSizeM
              elide: Text.ElideRight
            }
          }
        }

        Item {
          Layout.preferredWidth: Style.marginM
        }
      }

      // Password input
      RowLayout {
        Layout.fillWidth: true
        spacing: 0

        Item {
          Layout.preferredWidth: Style.marginM
        }

        Rectangle {
          id: passwordInputContainer
          Layout.fillWidth: true
          Layout.preferredHeight: 48
          radius: Style.iRadiusL
          color: Color.mSurface
          border.color: passwordInput.activeFocus ? Color.mPrimary : Qt.alpha(Color.mOutline, 0.3)
          border.width: passwordInput.activeFocus ? 2 : 1

          property bool passwordVisible: false

          // Ctrl + A to highlight the portion
          Shortcut {
            sequence: StandardKey.SelectAll
            enabled: passwordInput.activeFocus
            onActivated: passwordInput.selectAll()
          }

          // Esc to clear selection
          Shortcut {
            sequences: [StandardKey.Cancel]
            enabled: passwordInput.activeFocus && passwordInput.selectionStart !== passwordInput.selectionEnd
            onActivated: passwordInput.deselect()
          }

          Row {
            anchors.left: parent.left
            anchors.leftMargin: 18
            anchors.verticalCenter: parent.verticalCenter
            spacing: Style.marginL

            NIcon {
              icon: "login-2"
              pointSize: Style.fontSizeL
              color: passwordInput.activeFocus ? Color.mPrimary : Color.mOnSurfaceVariant
              anchors.verticalCenter: parent.verticalCenter
            }

            Row {
              spacing: 0

              Rectangle {
                width: 2
                height: 20
                color: Color.mPrimary
                visible: passwordInput.activeFocus && passwordInput.text.length === 0
                anchors.verticalCenter: parent.verticalCenter

                // Smooth fade animation (when animations enabled)
                SequentialAnimation on opacity {
                  loops: Animation.Infinite
                  running: root.animationsEnabled && passwordInput.activeFocus && passwordInput.text.length === 0
                  NumberAnimation {
                    to: 0
                    duration: 530
                  }
                  NumberAnimation {
                    to: 1
                    duration: 530
                  }
                }

                // Simple toggle (when animations disabled) — no per-frame repaints
                Timer {
                  interval: 530
                  running: !root.animationsEnabled && passwordInput.activeFocus && passwordInput.text.length === 0
                  repeat: true
                  onTriggered: parent.opacity = parent.opacity > 0.5 ? 0 : 1
                }
              }

              // Host for dots / plain text and the caret (caret x follows passwordInput.cursorPosition)
              Item {
                id: passwordVisualHost
                height: 20
                width: passwordInputContainer.passwordVisible ? Math.min(visiblePasswordPlainText.implicitWidth, 550) : Math.min(passwordDisplayContent.width, 550)
                anchors.verticalCenter: parent.verticalCenter

                readonly property real caretVisualX: {
                  const len = passwordInput.text.length;
                  if (len <= 0)
                    return 0;
                  if (passwordInputContainer.passwordVisible) {
                    const adv = passwordCaretFontMetrics.advanceWidth(passwordInput.text.substring(0, passwordInput.cursorPosition));
                    return Math.max(0, Math.min(adv, width));
                  }
                  const w = passwordDisplayContent.width;
                  if (w <= 0)
                    return 0;
                  return Math.max(0, Math.min((passwordInput.cursorPosition / len) * w, width));
                }

                // Password dots display with selection support
                Item {
                  width: Math.min(passwordDisplayContent.width, 550)
                  height: 20
                  visible: passwordInput.text.length > 0 && !passwordInputContainer.passwordVisible
                  anchors.left: parent.left
                  anchors.verticalCenter: parent.verticalCenter
                  clip: true

                  // Proportional selection highlight behind the dots
                  Rectangle {
                    id: selectionHighlight
                    visible: passwordInput.selectionStart !== passwordInput.selectionEnd && passwordInput.text.length > 0
                    color: Qt.alpha(Color.mPrimary, 0.8)
                    height: parent.height + Style.marginS
                    anchors.verticalCenter: parent.verticalCenter
                    x: (passwordInput.selectionStart / passwordInput.text.length) * passwordDisplayContent.width
                    width: ((passwordInput.selectionEnd - passwordInput.selectionStart) / passwordInput.text.length) * passwordDisplayContent.width
                  }

                  Row {
                    id: passwordDisplayContent
                    spacing: Style.marginXXXS
                    anchors.verticalCenter: parent.verticalCenter

                    Repeater {
                      id: iconRepeater
                      model: ScriptModel {
                        values: Array(passwordInput.text.length)
                      }

                      property list<string> passwordChars: ["circle-filled", "pentagon-filled", "michelin-star-filled", "square-rounded-filled", "guitar-pick-filled", "blob-filled", "triangle-filled"]

                      NIcon {
                        id: icon

                        required property int index
                        // This will be called with index = -1 when the TextInput is deleted
                        // So we make sur index is positive to avoid warning on array accesses
                        property bool drawCustomChar: index >= 0 && Settings.data.general.passwordChars
                        // Flip color when this dot falls inside the active selection range
                        property bool isSelected: index >= 0 && passwordInput.selectionStart !== passwordInput.selectionEnd && index >= passwordInput.selectionStart && index < passwordInput.selectionEnd

                        icon: drawCustomChar ? iconRepeater.passwordChars[index % iconRepeater.passwordChars.length] : "circle-filled"
                        pointSize: Style.fontSizeL
                        color: isSelected ? Color.mOnPrimary : Color.mPrimary
                        opacity: 1.0
                        scale: animationsEnabled ? 0.5 : 1
                        ParallelAnimation {
                          id: iconAnim
                          NumberAnimation {
                            target: icon
                            properties: "scale"
                            to: 1
                            duration: Style.animationFast
                            easing.type: Easing.BezierSpline
                            easing.bezierCurve: Easing.OutInBounce
                          }
                        }
                        Component.onCompleted: {
                          if (animationsEnabled) {
                            iconAnim.start();
                          }
                        }
                      }
                    }
                  }

                  // Mouse area for click-to-position and drag-to-select
                  MouseArea {
                    anchors.fill: parent
                    cursorShape: Qt.IBeamCursor

                    property int dragStartPos: 0
                    property bool pendingSelectAll: false

                    // Resets double-click state if user pauses too long between clicks
                    Timer {
                      id: doubleClickResetTimer
                      interval: 600
                      onTriggered: parent.pendingSelectAll = false
                    }

                    function charIndexFromX(mouseX) {
                      if (passwordInput.text.length === 0)
                        return 0;
                      var charWidth = passwordDisplayContent.width / passwordInput.text.length;
                      // floor so clicking anywhere on a dot selects that dot, not the next
                      return Math.max(0, Math.min(passwordInput.text.length - 1, Math.floor(mouseX / charWidth)));
                    }

                    onPressed: function (mouse) {
                      doubleClickResetTimer.stop();
                      passwordInput.forceActiveFocus();
                      dragStartPos = charIndexFromX(mouse.x);
                      passwordInput.cursorPosition = dragStartPos;
                    }

                    onPositionChanged: function (mouse) {
                      pendingSelectAll = false;
                      var curPos = charIndexFromX(mouse.x);
                      if (curPos <= dragStartPos) {
                        passwordInput.select(curPos, dragStartPos + 1);
                      } else {
                        passwordInput.select(dragStartPos, curPos + 1);
                      }
                    }

                    onDoubleClicked: function (mouse) {
                      passwordInput.forceActiveFocus();
                      if (pendingSelectAll) {
                        passwordInput.selectAll();
                        pendingSelectAll = false;
                      } else {
                        var pos = charIndexFromX(mouse.x);
                        passwordInput.select(pos, Math.min(pos + 1, passwordInput.text.length));
                        pendingSelectAll = true;
                        doubleClickResetTimer.restart();
                      }
                    }
                  }
                }

                NText {
                  id: visiblePasswordPlainText
                  text: passwordInput.text
                  color: Color.mPrimary
                  pointSize: Style.fontSizeM
                  visible: passwordInput.text.length > 0 && passwordInputContainer.passwordVisible
                  anchors.left: parent.left
                  anchors.verticalCenter: parent.verticalCenter
                  elide: Text.ElideRight
                  width: Math.min(implicitWidth, 550)
                }

                FontMetrics {
                  id: passwordCaretFontMetrics
                  font: visiblePasswordPlainText.font
                }

                Rectangle {
                  width: 2
                  height: 20
                  x: passwordVisualHost.caretVisualX
                  color: Color.mPrimary
                  // Hide the cursor when text is selected
                  visible: passwordInput.activeFocus && passwordInput.text.length > 0 && passwordInput.selectionStart === passwordInput.selectionEnd
                  anchors.verticalCenter: parent.verticalCenter

                  // Smooth fade animation (when animations enabled)
                  SequentialAnimation on opacity {
                    loops: Animation.Infinite
                    running: root.animationsEnabled && passwordInput.activeFocus && passwordInput.text.length > 0 && passwordInput.selectionStart === passwordInput.selectionEnd
                    NumberAnimation {
                      to: 0
                      duration: 530
                    }
                    NumberAnimation {
                      to: 1
                      duration: 530
                    }
                  }

                  // Simple toggle (when animations disabled) — no per-frame repaints
                  Timer {
                    interval: 530
                    running: !root.animationsEnabled && passwordInput.activeFocus && passwordInput.text.length > 0 && passwordInput.selectionStart === passwordInput.selectionEnd
                    repeat: true
                    onTriggered: parent.opacity = parent.opacity > 0.5 ? 0 : 1
                  }
                }
              }
            }
          }

          // Eye button to toggle password visibility
          Rectangle {
            anchors.right: submitButton.left
            anchors.rightMargin: 4
            anchors.verticalCenter: parent.verticalCenter
            width: 36
            height: 36
            radius: Math.min(Style.iRadiusL, width / 2)
            color: eyeButtonArea.containsMouse ? Color.mPrimary : "transparent"
            visible: passwordInput.text.length > 0
            enabled: !lockContext || !lockContext.unlockInProgress

            NIcon {
              anchors.centerIn: parent
              icon: parent.parent.passwordVisible ? "eye-off" : "eye"
              pointSize: Style.fontSizeM
              color: eyeButtonArea.containsMouse ? Color.mOnPrimary : Color.mOnSurfaceVariant

              Behavior on color {
                ColorAnimation {
                  duration: Style.animationFast
                  easing.type: Easing.OutCubic
                }
              }
            }

            MouseArea {
              id: eyeButtonArea
              anchors.fill: parent
              hoverEnabled: true
              cursorShape: Qt.PointingHandCursor
              onClicked: parent.parent.passwordVisible = !parent.parent.passwordVisible
            }

            Behavior on color {
              ColorAnimation {
                duration: Style.animationFast
                easing.type: Easing.OutCubic
              }
            }
          }

          // Submit button
          Rectangle {
            id: submitButton
            anchors.right: parent.right
            anchors.rightMargin: 8
            anchors.verticalCenter: parent.verticalCenter
            width: 36
            height: 36
            radius: Math.min(Style.iRadiusL, width / 2)
            color: submitButtonArea.containsMouse ? Color.mPrimary : "transparent"
            border.color: Color.mPrimary
            border.width: Style.borderS
            enabled: !lockContext || !lockContext.unlockInProgress

            NIcon {
              anchors.centerIn: parent
              icon: "arrow-forward"
              pointSize: Style.fontSizeM
              color: submitButtonArea.containsMouse ? Color.mOnPrimary : Color.mPrimary

              Behavior on color {
                ColorAnimation {
                  duration: Style.animationFast
                  easing.type: Easing.OutCubic
                }
              }
            }

            MouseArea {
              id: submitButtonArea
              anchors.fill: parent
              hoverEnabled: true
              cursorShape: Qt.PointingHandCursor
              onClicked: root.doUnlock()
            }

            Behavior on color {
              ColorAnimation {
                duration: Style.animationFast
                easing.type: Easing.OutCubic
              }
            }
          }

          Behavior on border.color {
            ColorAnimation {
              duration: Style.animationFast
              easing.type: Easing.OutCubic
            }
          }
        }

        Item {
          Layout.preferredWidth: Style.marginM
        }
      }

      // Session control buttons
      RowLayout {
        id: sessionButtonRow
        Layout.fillWidth: true
        Layout.preferredHeight: Settings.data.general.compactLockScreen ? 36 : 48
        Layout.alignment: Qt.AlignHCenter
        spacing: Style.marginM
        visible: Settings.data.general.showSessionButtonsOnLockScreen

        readonly property int buttonCount: Settings.data.general.showHibernateOnLockScreen ? 5 : 4
        readonly property real availableWidth: bottomContainer.width - 48
        readonly property real buttonWidth: (availableWidth - (buttonCount - 1) * spacing) / buttonCount
        readonly property real buttonHeight: sessionButtonRow.height

        Item {
          Layout.preferredWidth: sessionButtonRow.buttonWidth
          Layout.preferredHeight: sessionButtonRow.buttonHeight

          NButton {
            anchors.fill: parent
            icon: "logout"
            text: I18n.tr("common.logout")
            outlined: true
            backgroundColor: Color.mOnSurfaceVariant
            textColor: Color.mOnPrimary
            fontSize: Settings.data.general.compactLockScreen ? Style.fontSizeS : Style.fontSizeM
            iconSize: Settings.data.general.compactLockScreen ? Style.fontSizeM : Style.fontSizeL
            horizontalAlignment: Qt.AlignHCenter
            buttonRadius: Style.radiusL
            onClicked: startTimer("logout")
          }
        }

        Item {
          Layout.preferredWidth: sessionButtonRow.buttonWidth
          Layout.preferredHeight: sessionButtonRow.buttonHeight

          NButton {
            anchors.fill: parent
            icon: "suspend"
            text: I18n.tr("common.suspend")
            outlined: true
            backgroundColor: Color.mOnSurfaceVariant
            textColor: Color.mOnPrimary
            fontSize: Settings.data.general.compactLockScreen ? Style.fontSizeS : Style.fontSizeM
            iconSize: Settings.data.general.compactLockScreen ? Style.fontSizeM : Style.fontSizeL
            horizontalAlignment: Qt.AlignHCenter
            buttonRadius: Style.radiusL
            onClicked: startTimer("suspend")
          }
        }

        Item {
          Layout.preferredWidth: sessionButtonRow.buttonWidth
          Layout.preferredHeight: sessionButtonRow.buttonHeight
          visible: Settings.data.general.showHibernateOnLockScreen

          NButton {
            anchors.fill: parent
            icon: "hibernate"
            text: I18n.tr("common.hibernate")
            outlined: true
            backgroundColor: Color.mOnSurfaceVariant
            textColor: Color.mOnPrimary
            fontSize: Settings.data.general.compactLockScreen ? Style.fontSizeS : Style.fontSizeM
            iconSize: Settings.data.general.compactLockScreen ? Style.fontSizeM : Style.fontSizeL
            horizontalAlignment: Qt.AlignHCenter
            buttonRadius: Style.radiusL
            onClicked: startTimer("hibernate")
          }
        }

        Item {
          Layout.preferredWidth: sessionButtonRow.buttonWidth
          Layout.preferredHeight: sessionButtonRow.buttonHeight

          NButton {
            anchors.fill: parent
            icon: "reboot"
            text: I18n.tr("common.reboot")
            outlined: true
            backgroundColor: Color.mOnSurfaceVariant
            textColor: Color.mOnPrimary
            fontSize: Settings.data.general.compactLockScreen ? Style.fontSizeS : Style.fontSizeM
            iconSize: Settings.data.general.compactLockScreen ? Style.fontSizeM : Style.fontSizeL
            horizontalAlignment: Qt.AlignHCenter
            buttonRadius: Style.radiusL
            onClicked: startTimer("reboot")
          }
        }

        Item {
          Layout.preferredWidth: sessionButtonRow.buttonWidth
          Layout.preferredHeight: sessionButtonRow.buttonHeight

          NButton {
            anchors.fill: parent
            icon: "shutdown"
            text: I18n.tr("common.shutdown")
            outlined: true
            backgroundColor: Color.mError
            textColor: Color.mOnError
            fontSize: Settings.data.general.compactLockScreen ? Style.fontSizeS : Style.fontSizeM
            iconSize: Settings.data.general.compactLockScreen ? Style.fontSizeM : Style.fontSizeL
            horizontalAlignment: Qt.AlignHCenter
            buttonRadius: Style.radiusL
            onClicked: startTimer("shutdown")
          }
        }
      }
    }
  }
}
