class PostCreatePreflight
  class ValidationFailed < StandardError
    attr_reader :fields, :base_errors

    def initialize fields: { }, base_errors: []
      super('入力内容を確認してください．')
      @fields = fields
      @base_errors = base_errors
    end
  end

  def initialize attributes:, thumbnail: nil, host: nil
    @attributes = attributes.symbolize_keys
    @thumbnail = thumbnail
    @host = host
  end

  def run
    preview = PostImportPreviewer.new.preview_rows(
        rows: [preview_row],
        fetch_metadata: false).first
    if preview[:existing_post_id].present?
      return {
          url: preview[:url],
          title: preview[:attributes]['title'],
          thumbnail_base: preview[:attributes]['thumbnail_base'],
          tags: preview[:attributes]['tags'],
          parent_post_ids: preview[:attributes]['parent_post_ids'],
          original_created_from: preview[:attributes]['original_created_from'],
          original_created_before: preview[:attributes]['original_created_before'],
          duration: preview[:attributes]['duration'],
          video_ms: preview[:attributes]['video_ms'],
          display_tags: preview[:display_tags] || [],
          field_warnings: final_field_warnings(preview[:field_warnings] || { }),
          base_warnings: preview[:base_warnings],
          existing_post_id: preview[:existing_post_id],
          existing_post: existing_post_compact(preview[:existing_post_id]) }
    end

    if preview[:validation_errors].present?
      raise ValidationFailed.new(fields: preview[:validation_errors])
    end

    validate_thumbnail_upload!

    plan = PostCreatePlan.new(
        attributes: {
            url: preview[:url],
            title: preview[:attributes]['title'],
            thumbnail_base: preview[:attributes]['thumbnail_base'],
            tags: preview[:attributes]['tags'],
            parent_post_ids: preview[:attributes]['parent_post_ids'],
            original_created_from: preview[:attributes]['original_created_from'],
            original_created_before: preview[:attributes]['original_created_before'],
            duration: preview[:attributes]['duration'],
            video_ms: preview[:attributes]['video_ms'] }).build!

    {
        url: plan[:url],
        title: plan[:title],
        thumbnail_base: plan[:thumbnail_base],
        tags: plan[:tags],
        parent_post_ids: plan[:parent_post_ids],
        original_created_from: plan[:original_created_from],
        original_created_before: plan[:original_created_before],
        duration: plan[:duration],
        video_ms: plan[:video_ms],
        display_tags: plan[:display_tags],
        direct_tag_specs: plan[:direct_tag_specs],
        default_tag_specs: plan[:default_tag_specs],
        snapshot_tag_specs: plan[:snapshot_tag_specs],
        post_tag_specs: plan[:post_tag_specs],
        tag_sections: plan[:tag_sections],
        normalised_parent_post_ids: plan[:normalised_parent_post_ids],
        field_warnings: final_field_warnings(preview[:field_warnings] || { }),
        base_warnings: preview[:base_warnings],
        existing_post_id: preview[:existing_post_id],
        existing_post: existing_post_compact(preview[:existing_post_id]) }
  end

  private

  def preview_row
    {
        source_row: 1,
        url: @attributes[:url].to_s,
        attributes: {
            'title' => @attributes[:title].to_s,
            'thumbnail_base' => @attributes[:thumbnail_base].to_s,
            'original_created_from' => @attributes[:original_created_from].to_s,
            'original_created_before' => @attributes[:original_created_before].to_s,
            'duration' => @attributes[:duration].to_s,
            'video_ms' => @attributes[:video_ms],
            'tags' => @attributes[:tags].to_s,
            'parent_post_ids' => parent_post_ids_text },
        provenance: {
            'url' => 'manual',
            'title' => 'manual',
            'thumbnail_base' => 'manual',
            'original_created_from' => 'manual',
            'original_created_before' => 'manual',
            'duration' => 'manual',
            'video_ms' => 'manual',
            'tags' => 'manual',
            'parent_post_ids' => 'manual' },
        tag_sources: {
            'automatic' => '',
            'manual' => @attributes[:tags].to_s } }
  end

  def parent_post_ids_text
    Array(@attributes[:parent_post_ids]).flat_map { _1.to_s.split }.join(' ')
  end

  def validate_thumbnail_upload!
    return if @attributes[:thumbnail_base].present?
    return if @thumbnail.blank?

    PostThumbnailUploadValidator.validate!(@thumbnail)
  rescue PostThumbnailUploadValidator::InvalidUpload => e
    raise ValidationFailed.new(fields: { thumbnail: [e.message] })
  end

  def existing_post_compact post_id
    return nil if post_id.blank?

    post = Post.with_attached_thumbnail.find_by(id: post_id)
    PostCompactRepr.base(post, host: @host)
  end

  def final_field_warnings field_warnings
    thumbnail_warnings = (field_warnings['thumbnail_base'] || []).reject { _1 == 'サムネールなし' }
    if @attributes[:thumbnail_base].blank? && @thumbnail.blank?
      thumbnail_warnings = (thumbnail_warnings + ['サムネールなし']).uniq
    end

    next_warnings = field_warnings.except('thumbnail_base')
    next_warnings['thumbnail_base'] = thumbnail_warnings if thumbnail_warnings.present?
    next_warnings
  end
end
