# Copyright © 2025-26 l5yth & contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# frozen_string_literal: true

require "spec_helper"
require "sqlite3"

RSpec.describe PotatoMesh::App::Instances do
  let(:application_class) { PotatoMesh::Application }
  let(:week_seconds) { PotatoMesh::Config.week_seconds }

  # Execute the provided block with a configured SQLite connection.
  #
  # @param readonly [Boolean] whether the connection should be read-only.
  # @yieldparam db [SQLite3::Database] configured database handle.
  # @return [void]
  def with_db(readonly: false)
    db = SQLite3::Database.new(PotatoMesh::Config.db_path, readonly: readonly)
    db.busy_timeout = PotatoMesh::Config.db_busy_timeout_ms
    db.execute("PRAGMA foreign_keys = ON")
    yield db
  ensure
    db&.close
  end

  before do
    FileUtils.mkdir_p(File.dirname(PotatoMesh::Config.db_path))
    application_class.init_db unless application_class.db_schema_present?
    with_db do |db|
      db.execute("DELETE FROM instances")
    end
  end

  describe ".load_instances_for_api" do
    it "only returns instances updated within the configured rolling window" do
      fixed_time = Time.utc(2025, 1, 15, 12, 0, 0)
      allow(Time).to receive(:now).and_return(fixed_time)

      application_class.ensure_self_instance_record!

      recent_timestamp = fixed_time.to_i - (week_seconds / 2)
      stale_timestamp = fixed_time.to_i - week_seconds - 60

      with_db do |db|
        db.execute(
          "INSERT INTO instances (id, domain, pubkey, last_update_time, is_private) VALUES (?, ?, ?, ?, ?)",
          [
            "recent-instance",
            "recent.mesh.test",
            PotatoMesh::Application::INSTANCE_PUBLIC_KEY_PEM,
            recent_timestamp,
            0,
          ],
        )
        db.execute(
          "INSERT INTO instances (id, domain, pubkey, last_update_time, is_private) VALUES (?, ?, ?, ?, ?)",
          [
            "stale-instance",
            "stale.mesh.test",
            PotatoMesh::Application::INSTANCE_PUBLIC_KEY_PEM,
            stale_timestamp,
            0,
          ],
        )
        db.execute(
          "INSERT INTO instances (id, domain, pubkey, is_private) VALUES (?, ?, ?, ?)",
          [
            "missing-instance",
            "missing.mesh.test",
            PotatoMesh::Application::INSTANCE_PUBLIC_KEY_PEM,
            0,
          ],
        )
      end

      payload = application_class.load_instances_for_api
      domains = payload.map { |row| row["domain"] }
      lower_bound = fixed_time.to_i - week_seconds

      expect(domains).to include("recent.mesh.test")
      expect(domains).to include(application_class.app_constant(:INSTANCE_DOMAIN))
      expect(domains).not_to include("stale.mesh.test")
      expect(domains).not_to include("missing.mesh.test")
      expect(payload.all? { |row| row["lastUpdateTime"] >= lower_bound }).to be(true)
    end

    it "exposes contactLink when present and omits blank values" do
      fixed_time = Time.utc(2025, 2, 1, 12, 0, 0)
      allow(Time).to receive(:now).and_return(fixed_time)

      with_db do |db|
        db.execute(
          "INSERT INTO instances (id, domain, pubkey, last_update_time, is_private, contact_link) VALUES (?, ?, ?, ?, ?, ?)",
          [
            "instance-with-contact",
            "alpha.mesh.test",
            PotatoMesh::Application::INSTANCE_PUBLIC_KEY_PEM,
            fixed_time.to_i,
            0,
            " https://example.org/contact ",
          ],
        )
        db.execute(
          "INSERT INTO instances (id, domain, pubkey, last_update_time, is_private, contact_link) VALUES (?, ?, ?, ?, ?, ?)",
          [
            "instance-without-contact",
            "beta.mesh.test",
            PotatoMesh::Application::INSTANCE_PUBLIC_KEY_PEM,
            fixed_time.to_i,
            0,
            " \t ",
          ],
        )
      end

      payload = application_class.load_instances_for_api
      with_contact = payload.find { |row| row["domain"] == "alpha.mesh.test" }
      without_contact = payload.find { |row| row["domain"] == "beta.mesh.test" }

      expect(with_contact["contactLink"]).to eq("https://example.org/contact")
      expect(without_contact.key?("contactLink")).to be(false)
    end
  end
end
