defmodule Xema.RefRemoteSuiteTest do
  use ExUnit.Case, async: true

  import Xema, only: [valid?: 2]

  alias Test.RemoteLoaderExon

  describe "remote ref" do
    setup do
      %{schema: Xema.new({:ref, "http://localhost:1234/integer.exon"}, loader: RemoteLoaderExon)}
    end

    test "remote ref valid", %{schema: schema} do
      data = 1
      assert valid?(schema, data)
    end

    test "remote ref invalid", %{schema: schema} do
      data = "a"
      refute valid?(schema, data)
    end
  end

  describe "fragment within remote ref" do
    setup do
      %{
        schema:
          Xema.new({:ref, "http://localhost:1234/subSchemas.exon#/integer"},
            loader: RemoteLoaderExon
          )
      }
    end

    test "remote fragment valid", %{schema: schema} do
      data = 1
      assert valid?(schema, data)
    end

    test "remote fragment invalid", %{schema: schema} do
      data = "a"
      refute valid?(schema, data)
    end
  end

  describe "ref within remote ref" do
    setup do
      %{
        schema:
          Xema.new({:ref, "http://localhost:1234/subSchemas.exon#/refToInteger"},
            loader: RemoteLoaderExon
          )
      }
    end

    test "ref within ref valid", %{schema: schema} do
      data = 1
      assert valid?(schema, data)
    end

    test "ref within ref invalid", %{schema: schema} do
      data = "a"
      refute valid?(schema, data)
    end
  end

  describe "base URI change" do
    setup do
      %{
        schema:
          Xema.new(
            [
              id: "http://localhost:1234/",
              items: [id: "folder/", items: {:ref, "folderInteger.exon"}]
            ],
            loader: RemoteLoaderExon
          )
      }
    end

    test "base URI change ref valid", %{schema: schema} do
      data = [[1]]
      assert valid?(schema, data)
    end

    test "base URI change ref invalid", %{schema: schema} do
      data = [["a"]]
      refute valid?(schema, data)
    end
  end

  describe "base URI change - change folder" do
    setup do
      %{
        schema:
          Xema.new(
            {:map,
             [
               definitions: %{
                 baz: {:list, [id: "folder/", items: {:ref, "folderInteger.exon"}]}
               },
               id: "http://localhost:1234/scope_change_defs1.exon",
               properties: %{list: {:ref, "#/definitions/baz"}}
             ]},
            loader: RemoteLoaderExon
          )
      }
    end

    test "number is valid", %{schema: schema} do
      data = %{list: [1]}
      assert valid?(schema, data)
    end

    test "string is invalid", %{schema: schema} do
      data = %{list: ["a"]}
      refute valid?(schema, data)
    end
  end

  describe "base URI change - change folder in subschema" do
    setup do
      %{
        schema:
          Xema.new(
            {:map,
             [
               definitions: %{
                 baz: [
                   definitions: %{
                     bar: {:list, [items: {:ref, "folderInteger.exon"}]}
                   },
                   id: "folder/"
                 ]
               },
               id: "http://localhost:1234/scope_change_defs2.exon",
               properties: %{list: {:ref, "#/definitions/baz/definitions/bar"}}
             ]},
            loader: RemoteLoaderExon
          )
      }
    end

    test "number is valid", %{schema: schema} do
      data = %{list: [1]}
      assert valid?(schema, data)
    end

    test "string is invalid", %{schema: schema} do
      data = %{list: ["a"]}
      refute valid?(schema, data)
    end
  end

  describe "root ref in remote ref" do
    setup do
      %{
        schema:
          Xema.new(
            {:map,
             [
               id: "http://localhost:1234/object",
               properties: %{name: {:ref, "name.exon#/definitions/orNull"}}
             ]},
            loader: RemoteLoaderExon
          )
      }
    end

    test "string is valid", %{schema: schema} do
      data = %{name: "foo"}
      assert valid?(schema, data)
    end

    test "null is valid", %{schema: schema} do
      data = %{name: nil}
      assert valid?(schema, data)
    end

    test "object is invalid", %{schema: schema} do
      data = %{name: %{name: nil}}
      refute valid?(schema, data)
    end
  end
end
