package my

import java.util.Objects
import kotlin.Any
import kotlin.Boolean
import kotlin.Int
import kotlin.Long
import kotlin.String
import kotlin.text.StringBuilder
import org.pkl.core.Duration

object Mod {
  private fun appendProperty(
    builder: StringBuilder,
    name: String,
    value: Any?
  ) {
    builder.append("\n  ").append(name).append(" = ")
    val lines = value.toString().split("\n")
    builder.append(lines[0])
    for (i in 1..lines.lastIndex) {
      builder.append("\n  ").append(lines[i])
    }
  }

  open class Foo(
    open val one: Long
  ) {
    open fun copy(one: Long = this.one): Foo = Foo(one)

    override fun equals(other: Any?): Boolean {
      if (this === other) return true
      if (this.javaClass != other?.javaClass) return false
      other as Foo
      if (this.one != other.one) return false
      return true
    }

    override fun hashCode(): Int {
      var result = 1
      result = 31 * result + Objects.hashCode(this.one)
      return result
    }

    override fun toString(): String {
      val builder = StringBuilder(100)
      builder.append(Foo::class.java.simpleName).append(" {")
      appendProperty(builder, "one", this.one)
      builder.append("\n}")
      return builder.toString()
    }
  }

  open class None(
    one: Long
  ) : Foo(one) {
    open override fun copy(one: Long): None = None(one)

    override fun equals(other: Any?): Boolean {
      if (this === other) return true
      if (this.javaClass != other?.javaClass) return false
      other as None
      if (this.one != other.one) return false
      return true
    }

    override fun hashCode(): Int {
      var result = 1
      result = 31 * result + Objects.hashCode(this.one)
      return result
    }

    override fun toString(): String {
      val builder = StringBuilder(100)
      builder.append(None::class.java.simpleName).append(" {")
      appendProperty(builder, "one", this.one)
      builder.append("\n}")
      return builder.toString()
    }
  }

  open class Bar(
    one: Long,
    open val two: String
  ) : None(one) {
    open fun copy(one: Long = this.one, two: String = this.two): Bar = Bar(one, two)

    open override fun copy(one: Long): Bar = Bar(one, two)

    override fun equals(other: Any?): Boolean {
      if (this === other) return true
      if (this.javaClass != other?.javaClass) return false
      other as Bar
      if (this.one != other.one) return false
      if (this.two != other.two) return false
      return true
    }

    override fun hashCode(): Int {
      var result = 1
      result = 31 * result + Objects.hashCode(this.one)
      result = 31 * result + Objects.hashCode(this.two)
      return result
    }

    override fun toString(): String {
      val builder = StringBuilder(150)
      builder.append(Bar::class.java.simpleName).append(" {")
      appendProperty(builder, "one", this.one)
      appendProperty(builder, "two", this.two)
      builder.append("\n}")
      return builder.toString()
    }
  }

  class Baz(
    one: Long,
    two: String,
    val three: Duration
  ) : Bar(one, two) {
    fun copy(
      one: Long = this.one,
      two: String = this.two,
      three: Duration = this.three
    ): Baz = Baz(one, two, three)

    override fun copy(one: Long, two: String): Baz = Baz(one, two, three)

    override fun copy(one: Long): Baz = Baz(one, two, three)

    override fun equals(other: Any?): Boolean {
      if (this === other) return true
      if (this.javaClass != other?.javaClass) return false
      other as Baz
      if (this.one != other.one) return false
      if (this.two != other.two) return false
      if (this.three != other.three) return false
      return true
    }

    override fun hashCode(): Int {
      var result = 1
      result = 31 * result + Objects.hashCode(this.one)
      result = 31 * result + Objects.hashCode(this.two)
      result = 31 * result + Objects.hashCode(this.three)
      return result
    }

    override fun toString(): String {
      val builder = StringBuilder(200)
      builder.append(Baz::class.java.simpleName).append(" {")
      appendProperty(builder, "one", this.one)
      appendProperty(builder, "two", this.two)
      appendProperty(builder, "three", this.three)
      builder.append("\n}")
      return builder.toString()
    }
  }
}
