package ocelot.desktop.ui.widget.settings

import ocelot.desktop.color.Color
import ocelot.desktop.geometry.{Padding2D, Size2D}
import ocelot.desktop.graphics.{Graphics, IconSource}
import ocelot.desktop.ui.layout.LinearLayout
import ocelot.desktop.ui.widget.modal.notification.{NotificationDialog, NotificationType}
import ocelot.desktop.ui.widget._
import ocelot.desktop.ui.widget.tooltip.LabelTooltip
import ocelot.desktop.util.{FileUtils, Logging, OcelotPaths, Orientation}
import ocelot.desktop.{ColorScheme, OcelotDesktop, Settings}

import java.io.File
import javax.swing.JFileChooser
import scala.util.{Failure, Success}

class SystemSettingsTab extends SettingsTab with Logging {
  private val OpenComputersConfigResource = "/application.conf"

  override val icon: IconSource = IconSource.Icons.SettingsSystem
  override val label: String = "System"

  override def applySettings(): Unit = {
    if (Settings.get.autosave) {
      OcelotDesktop.resetAutosave()
    }
  }

  children :+= new PaddingBox(new Label("Set OpenComputers configuration file path:"), Padding2D(bottom = 8))

  private val textInput: TextInput = new TextInput(Settings.get.brainCustomConfigPath.getOrElse("")) {
    if (Settings.get.brainCustomConfigPath.isEmpty) placeholder = "not set / using default OpenComputers configuration"
    override def onInput(text: String): Unit = {
      Settings.get.brainCustomConfigPath = Some(text)
      restartWarning.isVisible = true
    }
  }

  children :+= new PaddingBox(
    new Widget {
      override val layout = new LinearLayout(this, orientation = Orientation.Horizontal)

      children :+= new PaddingBox(textInput, Padding2D(right = 8))

      children :+= new IconButton(
        IconSource.Icons.Folder,
        IconSource.Icons.Folder,
        releasedColor = ColorScheme("ButtonForeground"),
        pressedColor = ColorScheme("ButtonForegroundPressed"),
        drawBackground = true,
        padding = 3.5f,
        tooltip = Some("Search for OpenComputers configuration file"),
      ) {
        override def onClicked(): Unit = {
          OcelotDesktop.showFileChooserDialog(JFileChooser.OPEN_DIALOG, JFileChooser.FILES_ONLY) {
            case Some(dir) =>
              setConfigPath(dir.getCanonicalPath)
              Success(())
            case None => Success(())
          }
        }
      }
    },
    Padding2D(bottom = 4),
  )

  children :+= new PaddingBox(new Label("Generate new OpenComputers configuration file in:"),
    Padding2D(top = 8, bottom = 8))

  children :+= new Widget {
    children :+= new Button(new LabelTooltip(new File(OcelotPaths.openComputersConfigName).getCanonicalPath)) {
      override def text: String = "Current Directory"
      override def onClick(): Unit = {
        unpackConfig(new File(OcelotPaths.openComputersConfigName))
      }
    }
    children :+= new PaddingBox(
      new Button(new LabelTooltip(OcelotPaths.openComputersConfig.toString)) {
        override def text: String = "Config Directory"
        override def onClick(): Unit = {
          unpackConfig(OcelotPaths.openComputersConfig.toFile)
        }
      },
      Padding2D(left = 8),
    )
    children :+= new PaddingBox(
      new Button(new LabelTooltip("...")) {
        override def text: String = "Custom Path"
        override def onClick(): Unit = {
          OcelotDesktop.showFileChooserDialog(JFileChooser.SAVE_DIALOG, JFileChooser.FILES_ONLY) {
            case Some(file) =>
              unpackConfig(file)
              Success(())
            case None => Success(())
          }
        }
      },
      Padding2D(left = 8),
    )
  }

  children :+= new PaddingBox(
    new Checkbox("Workspace autosave", Settings.get.autosave) {
      override def minimumSize: Size2D = Size2D(512, 24)

      override def onValueChanged(value: Boolean): Unit = {
        Settings.get.autosave = value
        applySettings()
      }
    },
    Padding2D(top = 16),
  )

  children :+= new PaddingBox(
    new Widget {
      children :+= new PaddingBox(new Label("Workspace autosave period (seconds):"), Padding2D(top = 4, right = 8))

      children :+= new TextInput(Settings.get.autosavePeriod.toString) {
        override def onInput(text: String): Unit = {
          try {
            Settings.get.autosavePeriod = text.toInt
          } catch {
            case _: NumberFormatException =>
              logger.warn(s"Trying to set a non-number value ($text) to the `autosavePeriod` setting!");
          }
        }
      }
    },
    Padding2D(bottom = 8),
  )

  private def unpackConfig(file: File): Unit = {
    if (file.exists()) {
      new NotificationDialog(s"You are overriding an existing file!", NotificationType.Warning) {
        addButton("Proceed") {
          unpackAndOverrideConfig(file)
          close()
        }
      }.addCloseButton("Cancel").show()
    } else {
      unpackAndOverrideConfig(file)
    }
  }

  private def unpackAndOverrideConfig(file: File): Unit = {
    val path = FileUtils.unpackResource(OpenComputersConfigResource, file)
    path match {
      case Success(dir) =>
        logger.info(s"Saved OpenComputers configuration to: ${dir.getCanonicalPath}")
        setConfigPath(dir.getCanonicalPath)
      case Failure(exception) =>
        new NotificationDialog(
          s"Something went wrong!\n($exception)\nCheck the log file for a full stacktrace.",
          NotificationType.Error,
        ).addCloseButton().show()
    }
  }

  private def setConfigPath(path: String): Unit = {
    Settings.get.brainCustomConfigPath = Some(path)
    textInput.text = path
    restartWarning.isVisible = true
  }

  private val restartWarning: InvisibleLabel = new InvisibleLabel {
    override def isSmall: Boolean = true

    override def color: Color = ColorScheme("ErrorMessage")

    override def text = "Restart Ocelot to apply new configuration"
  }

  children :+= new PaddingBox(restartWarning, Padding2D(top = 4, bottom = 8))

  private class InvisibleLabel extends Label {
    var isVisible = false
    override def draw(g: Graphics): Unit = if (isVisible) super.draw(g)
  }
}
