class Iro::Position

def self.long

# ok
def self.long
  where( long_or_short: Iro::Strategy::LONG )
end

def self.short

# ok
def self.short
  where( long_or_short: Iro::Strategy::SHORT )
end

def begin_delta

def begin_delta
  strategy.send("begin_delta_#{strategy.kind}", self)
end

def breakeven

def breakeven
  strategy.send("breakeven_#{strategy.kind}", self)
end

def calc_nxt

def calc_nxt
  pos = self
  ## 7 days ahead - not configurable so far
  outs = Tda::Option.get_quotes({
    contractType: pos.put_call,
    expirationDate: next_expires_on,
    ticker: ticker,
  })
  outs_bk = outs.dup
  outs = outs.select do |out|
    out[:bidSize] + out[:askSize] > 0
  end
  if 'CALL' == pos.put_call
    ;
  elsif 'PUT' == pos.put_call
    outs = outs.reverse
  end
  ## next_inner_strike
  outs = outs.select do |out|
    if Iro::Strategy::CREDIT == pos.credit_or_debit
      if Iro::Strategy::SHORT == pos.long_or_short
        ## short credit call
        out[:strikePrice] >= strategy.next_inner_strike
      elsif Iro::Strategy::LONG == pos.long_or_short
        ## long credit put
        out[:strikePrice] <= strategy.next_inner_strike
      end
    else
      raise 'zz3 - @TODO: implement, debit spreads'
    end
  end
  puts! outs[0][:strikePrice], 'after calc next_inner_strike'
  puts! outs, 'outs'
  ## next_buffer_above_water
  outs = outs.select do |out|
    if Iro::Strategy::SHORT == pos.long_or_short
      out[:strikePrice] > strategy.next_buffer_above_water + strategy.stock.last
    elsif Iro::Strategy::LONG == pos.long_or_short
      out[:strikePrice] < strategy.stock.last - strategy.next_buffer_above_water
    else
      raise 'zz4 - this cannot happen'
    end
  end
  puts! outs[0][:strikePrice], 'after calc next_buffer_above_water'
  puts! outs, 'outs'
  ## next_inner_delta
  outs = outs.select do |out|
    if 'CALL' == pos.put_call
      out_delta  = out[:delta] rescue 1
      out_delta <= strategy.next_inner_delta
    elsif 'PUT' == pos.put_call
      out_delta  = out[:delta] rescue 0
      out_delta <= strategy.next_inner_delta
    else
      raise 'zz5 - this cannot happen'
    end
  end
  puts! outs[0][:strikePrice], 'after calc next_inner_delta'
  puts! outs, 'outs'
  inner = outs[0]
  outs = outs.select do |out|
    if 'CALL' == pos.put_call
      out[:strikePrice] >= inner[:strikePrice].to_f + strategy.next_spread_amount
    elsif 'PUT' == pos.put_call
      out[:strikePrice] <= inner[:strikePrice].to_f - strategy.next_spread_amount
    end
  end
  outer = outs[0]
  if inner && outer
    o_attrs = {
      expires_on: next_expires_on,
      put_call:   pos.put_call,
      stock_id:   pos.stock_id,
    }
    inner_ = Iro::Option.new(o_attrs.merge({
      strike:        inner[:strikePrice],
      begin_price: ( inner[:bid] + inner[:ask] )/2,
      begin_delta:   inner[:delta],
      end_price:   ( inner[:bid] + inner[:ask] )/2,
      end_delta:     inner[:delta],
    }))
    outer_ = Iro::Option.new(o_attrs.merge({
      strike:        outer[:strikePrice],
      begin_price: ( outer[:bid] + outer[:ask] )/2,
      begin_delta:   outer[:delta],
      end_price:   ( outer[:bid] + outer[:ask] )/2,
      end_delta:     outer[:delta],
    }))
    pos.autonxt ||= Iro::Position.new
    pos.autonxt.update({
      prev_gain_loss_amount: 'a',
      status:       'proposed',
      stock:        strategy.stock,
      inner:        inner_,
      outer:        outer_,
      inner_strike: inner_.strike,
      outer_strike: outer_.strike,
      begin_on:     Time.now.to_date,
      expires_on:   next_expires_on,
      purse:        purse,
      strategy:     strategy,
      quantity:     1,
      autoprev:     pos,
    })
    pos.autonxt.sync
    pos.autonxt.save!
    pos.save
    return pos
  else
    throw 'zmq - should not happen'
  end
end

def calc_rollp

# should_roll?
def calc_rollp
  self.next_reasons = []
  # self.next_symbol  = nil
  # self.next_delta   = nil
  out = strategy.send( "calc_rollp_#{strategy.kind}", self )
  self.rollp = out[0]
  self.next_reasons.push out[1]
  save
end

def current_underlying_strike

def current_underlying_strike
  Iro::Stock.find_by( ticker: ticker ).last
end

def end_delta

def end_delta
  strategy.send("end_delta_#{strategy.kind}", self)
end

def max_gain # each

each
def max_gain # each
  strategy.send("max_gain_#{strategy.kind}", self)
end

def max_loss # each

each
def max_loss # each
  strategy.send("max_loss_#{strategy.kind}", self)
end

def net_amount # each

each
def net_amount # each
  strategy.send("net_amount_#{strategy.kind}", self)
end

def net_percent

def net_percent
  net_amount / max_gain
end

def next_expires_on

# ok
def next_expires_on
  out = expires_on.to_datetime.next_occurring(:monday).next_occurring(:friday)
  if !out.workday?
    out = Time.previous_business_day(out)
  end
  return out
end

def prev_gain_loss_amount

def prev_gain_loss_amount
  out  = autoprev.outer.end_price - autoprev.inner.end_price
  out += inner.begin_price - outer.begin_price
end

def q; quantity; end

def q; quantity; end

def refresh

def refresh
  out = Tda::Option.get_quote({
    contractType:   'CALL',
    strike:         strike,
    expirationDate: expires_on,
    ticker:         ticker,
  })
  update({
    end_delta: out[:delta],
    end_price: out[:last],
  })
  print '^'
end

def sync

def sync
  inner.sync
  outer.sync
end

def to_s

def to_s
  out = "#{stock} (#{q}) #{expires_on.to_datetime.strftime('%b %d')} #{strategy.long_or_short} ["
  if Iro::Strategy::LONG == long_or_short
    if outer.strike
      out = out + "$#{outer.strike}->"
    end
    out = out + "$#{inner.strike}"
  else
    out = out + "$#{inner.strike}"
    if outer.strike
      out = out + "<-$#{outer.strike}"
    end
  end
  out += "] "
  return out
end