require "rails_helper"


RSpec.describe "nico:sync" do
  def stub_python(json_array)
    status = instance_double(Process::Status, success?: true)
    allow(Open3).to receive(:capture3).and_return([json_array.to_json, "", status])
  end

  def create_tag!(name, category:)
    tn = TagName.find_or_create_by!(name: name.to_s.strip)
    Tag.find_or_create_by!(tag_name_id: tn.id) { |t| t.category = category }
  end

  def link_nico_to_tag!(nico_tag, tag)
    NicoTagRelation.create!(nico_tag_id: nico_tag.id, tag_id: tag.id)
  end

  it "既存 post を見つけて、nico tag と linked tag を追加し、差分が出たら bot を付ける" do
    # 既存 post（正規表現で拾われるURL）
    post = Post.create!(title: "old", url: "https://www.nicovideo.jp/watch/sm9", uploaded_user: nil)

    # 既存の非nicoタグ（kept_non_nico_ids）
    kept_general = create_tag!("spec_kept", category: "general")
    PostTag.create!(post: post, tag: kept_general)

    # 追加される linked tag を準備（nico tag に紐付く一般タグ）
    linked = create_tag!("spec_linked", category: "general")
    nico = create_tag!("nico:AAA", category: "nico")
    link_nico_to_tag!(nico, linked)

    # bot / tagme は task 内で使うので作っておく（Tag.bot/tagme がある前提）
    Tag.bot
    Tag.tagme

    # pythonの出力（AAA が付く）
    stub_python([{
        'code' => 'sm9',
        'title' => 't',
        'tags' => ['AAA'],
        'uploaded_at' => '2026-01-01 12:34:56',
        'deleted_at' => '2026-01-31 00:00:00' }])

    # 外部HTTPは今回「既存 post なので呼ばれない」はずだが、念のため塞ぐ
    allow(URI).to receive(:open).and_return(StringIO.new("<html></html>"))

    run_rake_task("nico:sync")

    post.reload
    active_tag_names = post.tags.joins(:tag_name).pluck("tag_names.name")

    expect(active_tag_names).to include("spec_kept")
    expect(active_tag_names).to include("nico:AAA")
    expect(active_tag_names).to include("spec_linked")

    expect(post.original_created_from).to eq(Time.iso8601('2026-01-01T03:34:00Z'))
    expect(post.original_created_before).to eq(Time.iso8601('2026-01-01T03:35:00Z'))

    # 差分が出るので bot が付く（kept_non_nico_ids != desired_non_nico_ids）
    expect(active_tag_names).to include("bot操作")
  end

  it "既存 post にあった古い nico tag は active から外され、履歴として discard される" do
    post = Post.create!(title: "old", url: "https://www.nicovideo.jp/watch/sm9", uploaded_user: nil)

    # 旧nicoタグ（今回の同期結果に含まれない）
    old_nico = create_tag!("nico:OLD", category: "nico")
    old_pt = PostTag.create!(post: post, tag: old_nico)
    expect(old_pt.discarded_at).to be_nil

    # 今回は NEW のみ欲しい
    new_nico = create_tag!("nico:NEW", category: "nico")

    # bot/tagme 念のため
    Tag.bot
    Tag.tagme

    stub_python([{ "code" => "sm9", "title" => "t", "tags" => ["NEW"] }])
    allow(URI).to receive(:open).and_return(StringIO.new("<html></html>"))

    run_rake_task("nico:sync")

    # OLD は active から外れる（discarded_at が入る）
    old_pts = PostTag.where(post_id: post.id, tag_id: old_nico.id).order(:id).to_a
    expect(old_pts.last.discarded_at).to be_present

    # NEW は active にいる
    post.reload
    active_names = post.tags.joins(:tag_name).pluck("tag_names.name")
    expect(active_names).to include("nico:NEW")
    expect(active_names).not_to include("nico:OLD")
  end
end
