import expect from "expect"
import React from "react"
import { configure, mount } from "enzyme"
import Adapter from "enzyme-adapter-react-15"
import { fromJS, List } from "immutable"

import AddForm from "src/standalone/topbar-insert/forms/components/AddForm"
import FormChild from "src/standalone/topbar-insert/forms/components/FormChild"
import FormDropdown from "src/standalone/topbar-insert/forms/components/FormDropdown"
import FormInput from "src/standalone/topbar-insert/forms/components/FormInput"
import FormInputWrapper from "src/standalone/topbar-insert/forms/components/FormInputWrapper"
import FormMap from "src/standalone/topbar-insert/forms/components/FormMap"
import InsertForm from "src/standalone/topbar-insert/forms/components/InsertForm"
import InsertFormInput from "src/standalone/topbar-insert/forms/components/InsertFormInput"
import InsertFormList from "src/standalone/topbar-insert/forms/components/InsertFormList"

import { pathForm, pathObject } from "src/standalone/topbar-insert/forms/form-objects/path-object"
import { operationForm, operationObject } from "src/standalone/topbar-insert/forms/form-objects/operation-object"
import { infoForm, infoObject } from "src/standalone/topbar-insert/forms/form-objects/info-object"
import { licenseForm} from "src/standalone/topbar-insert/forms/form-objects/license-object"
import { contactForm } from "src/standalone/topbar-insert/forms/form-objects/contact-object"
import { tagsForm, tagsObject } from "src/standalone/topbar-insert/forms/form-objects/tags-object"
import { tagForm } from "src/standalone/topbar-insert/forms/form-objects/tag-object"
import { serversForm, serversObject } from "src/standalone/topbar-insert/forms/form-objects/servers-object"
import { serverVariableForm } from "src/standalone/topbar-insert/forms/form-objects/server-variable-object"
import { externalDocumentationForm } from "src/standalone/topbar-insert/forms/form-objects/external-documentation-object"
import { addOperationTagsForm, addOperationTagsObject } from "src/standalone/topbar-insert/forms/form-objects/add-operation-tags"
import { selectOperationForm } from "src/standalone/topbar-insert/forms/form-objects/select-operation"
import { selectResponseForm } from "src/standalone/topbar-insert/forms/form-objects/select-response"
import { exampleObject, exampleForm } from "src/standalone/topbar-insert/forms/form-objects/example-value-object"

configure({ adapter: new Adapter() })

describe("editor topbar insert forms", function() {
  this.timeout(10 * 1000)
  let components, props

  beforeEach(() => {
    components = {
      FormDropdown,
      AddForm,
      FormChild,
      FormInput,
      FormInputWrapper,
      FormMap,
      InsertForm,
      InsertFormInput,
      InsertFormList
    }

    props = {
      getComponent: (c) => components[c]
    }
  })


  describe("operation object", function () {
    let form = operationForm(null, [])
  
    const tag = form.getIn(["tags", "defaultItem"])(null, [])

    form = form
      .setIn(["path", "value"], "/testpath")
      .setIn(["summary", "value"], "test summary")
      .setIn(["description", "value"], "test description")
      .setIn(["operationid", "value"], "testid")
      .setIn(["tags", "value"], new List([tag.setIn(["tag", "value"], "test tag" )]))
    
    const object = operationObject(form)

    it("should correctly process the operation form into the operation object", () => {  
      const expected = {
        summary: "test summary",
        description: "test description",
        operationId: "testid",
        tags: ["test tag"],
        responses: {
          default: {
            description: "Default error sample response"
          }
        }
      }
  
      expect(object).toEqual(expected)
    })
  
    it ("should correctly render the form UI for the form object", () => {
      const element = <InsertForm {...props} formData={form} />
      const wrapper = mount(element)
  
      expect(wrapper.find("input").length).toEqual(4)
      expect(wrapper.find("select").length).toEqual(2)
    })
  })

  describe("info object", () => {
    const license = licenseForm(null, [], null)
    .setIn(["value", "name", "value"], "test name")
    .setIn(["value", "url", "value"], "test url")
    
    const contact = contactForm(null, [])
      .setIn(["value", "name", "value"], "test name")
      .setIn(["value", "url", "value"], "test url")
      .setIn(["value", "email", "value"], "testemail@test.com")

    let form = infoForm(null, [])
      .setIn(["title", "value"], "test title")
      .setIn(["version", "value"], "test version")
      .setIn(["description", "value"], "test description")
      .setIn(["termsofservice", "value"], "testtermsofservice")
      .setIn(["license"], license)
      .setIn(["contact"], contact)

    it("should correctly process the info form into the info object", () => {        
      const object = infoObject(form)
  
      const expected = {
        title: "test title",
        version: "test version",
        description: "test description",
        termsOfService: "testtermsofservice",
        license: {
          name: "test name",
          url: "test url"
        },
        contact: {
          name: "test name",
          url: "test url",
          email: "testemail@test.com"
        }
      }
  
      expect(object).toEqual(expected)
    })

    it ("should correctly render the form UI for the form object", () => {
      const element = <InsertForm {...props} formData={form} />
      const wrapper = mount(element)
  
      expect(wrapper.find("input").length).toEqual(4)
    })
  })

  describe("path object", () => {
    let form = pathForm(null, [])

    // Set some values as though the user had entered data
    form = form
      .setIn(["path", "value"], "/test")
      .setIn(["summary", "value"], "test summary")
      .setIn(["description", "value"], "test description")

    it("should correctly process the path form into the path object", () => {  
      const object = pathObject(form)
      const expected = {
        key: "/test",
        value: {
          summary: "test summary",
          description: "test description"
        }
      }
      expect(object).toEqual(expected)
    })

    it ("should correctly render the form UI for the form object", () => {
      const element = <InsertForm {...props} formData={form} />
      const wrapper = mount(element)
  
      expect(wrapper.find("input").length).toEqual(3)
    })
  })

  describe("tag declarations object", () => {
    let form = tagsForm(null, [])
  
    const externalDocs = externalDocumentationForm(null, [])
      .setIn(["url", "value"], "test url")
      .setIn(["description", "value"], "test description")
  
    const tag = tagForm(null, [])
      .setIn(["name", "value"], "test tag name")
      .setIn(["description", "value"], "test description")
      .setIn(["externalDocs", "value"], externalDocs)

    // Set some values as though the user had entered data
    form = form.setIn(["tags", "value"], new List([tag]))

    it("should correctly process the tag declarations form into the tags object", () => {
      const object = tagsObject(form)
      const expected = [
        {
          name: "test tag name",
          description: "test description",
          externalDocs: {
            url: "test url",
            description: "test description"
          }
        }
      ]
      expect(object).toEqual(expected)
    })  

    it ("should correctly render the form UI for the form object", () => {
      const element = <InsertForm {...props} formData={form} />
      const wrapper = mount(element)
  
      expect(wrapper.find("input").length).toEqual(2)
    })
  })

  describe("servers object", () => {
    let form = serversForm(null, [])
    const serverVariable = serverVariableForm(null, [])
      .setIn(["value", 0, "value", "default", "value"], "test default")
      .setIn(["value", 0, "value", "enum", "value"], fromJS([{ value: "test enum value"}]) )
      .setIn(["value", 0, "value", "vardescription", "value"], "test var description")
      .setIn(["value", 0, "keyValue"], "keyvalue")

    form = form
      .setIn(["servers", "value", 0, "url", "value"], "test url")
      .setIn(["servers", "value", 0, "description", "value"], "test description")
      .setIn(["servers", "value", 0, "variables"], serverVariable)

    it ("should correctly process the servers form into the servers object", () => {  
      const object = serversObject(form)
      const expected = [
        {
          url: "test url",
          description: "test description",
          variables: {
            keyvalue: {
              default: "test default",
              description: "test var description",
              enum: [
                "test enum value"
              ]
            }
          }
        }
      ]
  
      expect(object).toEqual(expected)
    })

    it ("should correctly render the form UI for the form object", () => {
      const element = <InsertForm {...props} formData={form} />
      const wrapper = mount(element)
  
      expect(wrapper.find("input").length).toEqual(6)
    })
  })

  describe("add tags object", () => {
    const selectOperation = selectOperationForm(null, [])
        .setIn(["path", "value"], "/test")
        .setIn(["operation", "value"], "GET")
  
    let form = addOperationTagsForm(null, [])
        .setIn(["selectoperation", "value"], selectOperation)
        .setIn(["tags", "value", 0, "tag", "value"], "test tag")

    it ("should correctly process the add tags to operation into the add tags object", () => {  
      const object = addOperationTagsObject(form)
  
      const expected = {
        selectedOperation: ["paths", "/test", "GET"],
        tags: [
          "test tag"
        ]
      }
  
      expect(object).toEqual(expected)
    })

    it ("should correctly render the form UI for the form object", () => {
      const element = <InsertForm {...props} formData={form} />
      const wrapper = mount(element)
  
      expect(wrapper.find("input").length).toEqual(1)
      expect(wrapper.find("select").length).toEqual(2)
    })
  })

  describe("add example response object", () => {
    const selectResponse = selectResponseForm(null, [])
      .setIn(["path", "value"], "/test")
      .setIn(["operation", "value"], "GET")
      .setIn(["response", "value"], "200")
      .setIn(["mediatype", "value"], "application/json")
  
    let form = exampleForm(null, [])
        .setIn(["selectresponse", "value"], selectResponse)
        .setIn(["exampleName", "value"], "sample example name")
        .setIn(["exampleValue", "value"], "sample example value")

    it ("should correctly process the add example form into the form values object", () => {  
      const object = exampleObject(form)
  
      const expected = {
        responsePath: ["paths", "/test", "GET", "responses", "200", "content", "application/json", "examples"],
        exampleValue: "sample example value",
        exampleName: "sample example name"
      }
  
      expect(object).toEqual(expected)
    })

    it ("should correctly render the form UI for the form object", () => {
      const element = <InsertForm {...props} formData={form} />
      const wrapper = mount(element)
  
      expect(wrapper.find("input").length).toEqual(1)
      expect(wrapper.find("select").length).toEqual(4)
    })
  })
})
