module Nodes
  alias Embedded = EmbeddedLink | EmbeddedContent | GithubGist
  alias Leaf = Text | Image | Embedded
  alias Child = Container | Leaf | Empty
  alias Children = Array(Child)

  class Container
    getter children : Children

    def initialize(@children : Children)
    end

    def ==(other : Container)
      other.children == children
    end

    def empty?
      children.empty? || children.each(&.empty?)
    end
  end

  class Empty
    def empty?
      true
    end
  end

  class BlockQuote < Container
  end

  class Code < Container
  end

  class Emphasis < Container
  end

  class Figure < Container
  end

  class FigureCaption < Container
  end

  class Heading1 < Container
  end

  class Heading2 < Container
  end

  class Heading3 < Container
  end

  class ListItem < Container
  end

  class MixtapeEmbed < Container
  end

  class OrderedList < Container
  end

  class Paragraph < Container
  end

  class Preformatted < Container
  end

  class Strong < Container
  end

  class UnorderedList < Container
  end

  class Text
    getter content : String

    def initialize(@content : String)
    end

    def ==(other : Text)
      other.content == content
    end

    def empty?
      content.empty?
    end
  end

  class Image
    IMAGE_HOST      = "https://cdn-images-1.medium.com/fit/c"
    MAX_WIDTH       = 800
    FALLBACK_HEIGHT = 600

    getter originalHeight : Int32
    getter originalWidth : Int32

    def initialize(
      @src : String,
      originalWidth : Int32?,
      originalHeight : Int32?
    )
      @originalWidth = originalWidth || MAX_WIDTH
      @originalHeight = originalHeight || FALLBACK_HEIGHT
    end

    def ==(other : Image)
      other.src == src
    end

    def src
      [IMAGE_HOST, width, height, @src].join("/")
    end

    def width
      [originalWidth, MAX_WIDTH].min.to_s
    end

    def height
      if originalWidth > MAX_WIDTH
        (originalHeight * ratio).round.to_i.to_s
      else
        originalHeight.to_s
      end
    end

    private def ratio
      MAX_WIDTH / originalWidth
    end

    def empty?
      false
    end
  end

  class EmbeddedContent
    MAX_WIDTH = 800

    getter src : String

    def initialize(@src : String, @originalWidth : Int32, @originalHeight : Int32)
    end

    def width
      [@originalWidth, MAX_WIDTH].min.to_s
    end

    def height
      if @originalWidth > MAX_WIDTH
        (@originalHeight * ratio).round.to_i.to_s
      else
        @originalHeight.to_s
      end
    end

    private def ratio
      MAX_WIDTH / @originalWidth
    end

    def ==(other : EmbeddedContent)
      other.src == src && other.width == width && other.height == height
    end

    def empty?
      false
    end
  end

  class EmbeddedLink
    getter href : String

    def initialize(@href : String)
    end

    def domain
      URI.parse(href).host
    end

    def ==(other : EmbeddedLink)
      other.href == href
    end

    def empty?
      false
    end
  end

  class Anchor < Container
    getter href : String

    def initialize(@children : Children, @href : String)
    end

    def ==(other : Anchor)
      other.children == children && other.href == href
    end

    def empty?
      false
    end
  end

  class UserAnchor < Container
    USER_BASE_URL = "https://medium.com/u/"

    getter href : String

    def initialize(@children : Children, user_id : String)
      @href = USER_BASE_URL + user_id
    end

    def ==(other : UserAnchor)
      other.children == children && other.href == href
    end

    def empty?
      false
    end
  end

  class GithubGist
    def initialize(@href : String)
    end

    def src
      "#{@href}.js"
    end

    def ==(other : GithubGist)
      other.src == src
    end

    def empty?
      false
    end
  end
end
