module BCDD
  class Result
    VERSION: String
  end
end

class BCDD::Result
  attr_reader _type: BCDD::Result::Type
  attr_reader value: untyped
  attr_reader subject: untyped

  def initialize: (type: Symbol, value: untyped, ?subject: untyped) -> void

  def type: -> Symbol

  def success?: (?Symbol type) -> bool
  def failure?: (?Symbol type) -> bool

  def value_or: { () -> untyped } -> untyped

  def ==: (untyped) -> bool
  alias eql? ==

  def hash: -> Integer

  def inspect: -> String

  def on: (*Symbol) { (untyped, Symbol) -> void } -> BCDD::Result
  def on_success: (*Symbol) { (untyped, Symbol) -> void } -> BCDD::Result
  def on_failure: (*Symbol) { (untyped, Symbol) -> void } -> BCDD::Result

  def and_then: (?Symbol method_name) { (untyped) -> untyped } -> BCDD::Result

  def handle: { (BCDD::Result::Handler) -> void } -> untyped

  alias data value
  alias data_or value_or
  alias on_type on

  private

  def call_subject_method: (Symbol) -> BCDD::Result
  def ensure_result_object: (untyped, origin: Symbol) -> BCDD::Result
end

class BCDD::Result
  class Failure < BCDD::Result
  end

  def self.Success: (Symbol type, ?untyped value) -> BCDD::Result::Success
end

class BCDD::Result
  class Success < BCDD::Result
  end

  def self.Failure: (Symbol type, ?untyped value) -> BCDD::Result::Failure
end

class BCDD::Result
  class Handler
    UNDEFINED: Object

    def initialize: (BCDD::Result) -> void

    def []: (*Symbol) { (untyped, Symbol) -> void } -> untyped
    def failure: (*Symbol) { (untyped, Symbol) -> void } -> untyped
    def success: (*Symbol) { (untyped, Symbol) -> void } -> untyped

    alias type []

    private

    attr_reader _type: BCDD::Result::Type
    attr_reader result: BCDD::Result

    def outcome?: -> bool

    def outcome: -> untyped

    def outcome=: (Proc) -> void
  end
end

module BCDD
  module Resultable
    def Success: (Symbol type, ?untyped value) -> BCDD::Result::Success

    def Failure: (Symbol type, ?untyped value) -> BCDD::Result::Failure
  end
end

class BCDD::Result
  class Type
    attr_reader to_sym: Symbol

    def initialize: (Symbol) -> void

    def in?: (Array[Symbol], allow_empty: bool) -> bool
  end
end

class BCDD::Result
  class Error < ::StandardError
    def self.build: (**untyped) -> BCDD::Result::Error

    class NotImplemented < BCDD::Result::Error
    end

    class MissingTypeArgument < BCDD::Result::Error
    end

    class UnexpectedOutcome < BCDD::Result::Error
      def self.build: (outcome: untyped, origin: Symbol)
          -> BCDD::Result::Error::UnexpectedOutcome
    end

    class WrongResultSubject < BCDD::Result::Error
      def self.build: (given_result: BCDD::Result, expected_subject: untyped)
          -> BCDD::Result::Error::WrongResultSubject
    end

    class WrongSubjectMethodArity < BCDD::Result::Error
      def self.build: (subject: untyped, method: ::Method)
        -> BCDD::Result::Error::WrongSubjectMethodArity
    end
  end
end