require 'icalendar/tzinfo'

class EasyCalendarEvent

  attr_reader :object

  delegate :id, to: :object

  def initialize(object)
    @object = object
  end

  def self.create(object)
    "#{object.class.name}CalendarEvent".constantize.new(object)
  end

  def uid
    "availability-#{self.class.name.underscore.dasherize}-#{self.id}"
  end

  def title
    raise NotImplementedError
  end

  def starts_at
    raise NotImplementedError
  end

  def ends_at
    raise NotImplementedError
  end

  def all_day?
    raise NotImplementedError
  end

  def location
    raise NotImplementedError
  end

  def url(context = nil)
    raise NotImplementedError
  end

  def organizer
    raise NotImplementedError
  end

  def attendees
    []
  end

  def to_ical_datetime(value)
    value.to_datetime.utc.strftime('%Y%m%dT%H%M%SZ') if value
  end

  # All day event is stil saved as Time shifted to DB time zone
  def to_ical_date(value)
    return unless value

    unless value.is_a?(Date)
      zone = User.current.time_zone
      value = zone ? value.in_time_zone(zone) : (value.utc? ? value.localtime : value)
    end

    Icalendar::Values::Date.new(value)
  end

  def to_ical
    event = Icalendar::Event.new
    event.uid          = uid
    event.url          = url
    event.summary      = title
    event.location     = location

    if all_day?
      event.dtstart = to_ical_date(starts_at)
      event.dtend   = to_ical_date(ends_at)
    else
      event.dtstart = to_ical_datetime(starts_at)
      event.dtend   = to_ical_datetime(ends_at)
    end

    event.organizer    = organizer
    event.attendee     = attendees
    event.ip_class     = 'PUBLIC'
    event
  end

  def to_icalendar
    tzinfo = TZInfo::Timezone.get(User.current.time_zone && User.current.time_zone.tzinfo.identifier || 'UTC')
    timezone = tzinfo.ical_timezone(starts_at)

    calendar = Icalendar::Calendar.new
    calendar.add_timezone(timezone)
    calendar.add_event(to_ical)
    calendar
  end

  def self.default_url_options
    Mailer.default_url_options
  end

end
