package loads

import (
	"encoding/json"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestUnknownSpecVersion(t *testing.T) {
	_, err := Analyzed([]byte{}, "0.9")
	assert.Error(t, err)
}

func TestDefaultsTo20(t *testing.T) {
	d, err := Analyzed(PetStoreJSONMessage, "")

	assert.NoError(t, err)
	assert.NotNil(t, d)
	assert.Equal(t, "2.0", d.Version())
	// assert.Equal(t, "2.0", d.data["swagger"].(string))
	assert.Equal(t, "/api", d.BasePath())
}

func TestLoadsYAMLContent(t *testing.T) {
	d, err := Analyzed(json.RawMessage([]byte(YAMLSpec)), "")
	if assert.NoError(t, err) {
		if assert.NotNil(t, d) {
			sw := d.Spec()
			assert.Equal(t, "1.0.0", sw.Info.Version)
		}
	}
}

// for issue 11
func TestRegressionExpand(t *testing.T) {
	swaggerFile := "fixtures/yaml/swagger/1/2/3/4/swagger.yaml"
	document, err := Spec(swaggerFile)
	assert.NoError(t, err)
	assert.NotNil(t, document)
	d, err := document.Expanded()
	assert.NoError(t, err)
	assert.NotNil(t, d)
	b, _ := d.Spec().MarshalJSON()
	assert.JSONEq(t, expectedExpanded, string(b))
}

func TestFailsInvalidJSON(t *testing.T) {
	_, err := Analyzed(json.RawMessage([]byte("{]")), "")

	assert.Error(t, err)
}

var YAMLSpec = `swagger: '2.0'

info:
  version: "1.0.0"
  title: Simple Search API
  description: |
    A very simple api description that makes a x-www-form-urlencoded only API to submit searches.

produces:
  - application/json

consumes:
  - application/json

paths:
  /search:
    post:
      operationId: search
      summary: searches tasks
      description: searches the task titles and descriptions for a match
      consumes:
        - application/x-www-form-urlencoded
      parameters:
        - name: q
          in: formData
          type: string
          description: the search string
          required: true
  /tasks:
    get:
      operationId: getTasks
      summary: Gets Task objects.
      description: |
        Optional query param of **size** determines
        size of returned array
      tags:
        - tasks
      parameters:
        - name: size
          in: query
          description: Size of task list
          type: integer
          format: int32
          default: 20
        - name: completed
          in: query
          description: when true shows completed tasks
          type: boolean

      responses:
        default:
          description: Generic Error
        200:
          description: Successful response
          headers:
            X-Rate-Limit:
              type: integer
              format: int32
            X-Rate-Limit-Remaining:
              type: integer
              format: int32
              default: 42
            X-Rate-Limit-Reset:
              type: integer
              format: int32
              default: "1449875311"
            X-Rate-Limit-Reset-Human:
              type: string
              default: 3 days
            X-Rate-Limit-Reset-Human-Number:
              type: string
              default: 3
            Access-Control-Allow-Origin:
              type: string
              default: "*"
          schema:
            type: array
            items:
              $ref: "#/definitions/Task"
    post:
      operationId: createTask
      summary: Creates a 'Task' object.
      description: |
        Validates the content property for length etc.
      parameters:
        - name: body
          in: body
          schema:
            $ref: "#/definitions/Task"
      tags:
        - tasks
      responses:
        default:
          description: Generic Error
        201:
          description: Task Created

  /tasks/{id}:
    parameters:
      - name: id
        in: path
        type: integer
        format: int32
        description: The id of the task
        required: true
        minimum: 1
    put:
      operationId: updateTask
      summary: updates a task.
      description: |
        Validates the content property for length etc.
      tags:
        - tasks
      parameters:
        - name: body
          in: body
          description: the updated task
          schema:
            $ref: "#/definitions/Task"
      responses:
        default:
          description: Generic Error
        200:
          description: Task updated
          schema:
            $ref: "#/definitions/Task"
    delete:
      operationId: deleteTask
      summary: deletes a task
      description: |
        Deleting a task is irrevocable.
      tags:
        - tasks
      responses:
        default:
          description: Generic Error
        204:
          description: Task Deleted


definitions:
  Task:
    title: A Task object
    description: |
      This describes a task. Tasks require a content property to be set.
    required:
      - content
    type: object
    properties:
      id:
        title: the unique id of the task
        description: |
          This id property is autogenerated when a task is created.
        type: integer
        format: int64
        readOnly: true
      content:
        title: The content of the task
        description: |
          Task content can contain [GFM](https://help.github.com/articles/github-flavored-markdown/).
        type: string
        minLength: 5
      completed:
        title: when true this task is completed
        type: boolean
      creditcard:
        title: the credit card format usage
        type: string
        format: creditcard
      createdAt:
        title: task creation time
        type: string
        format: date-time
        readOnly: true
`

// PetStoreJSONMessage json raw message for Petstore20
var PetStoreJSONMessage = json.RawMessage([]byte(PetStore20))

// PetStore20 json doc for swagger 2.0 pet store
const PetStore20 = `{
  "swagger": "2.0",
  "info": {
    "version": "1.0.0",
    "title": "Swagger Petstore",
    "contact": {
      "name": "Wordnik API Team",
      "url": "http://developer.wordnik.com"
    },
    "license": {
      "name": "Creative Commons 4.0 International",
      "url": "http://creativecommons.org/licenses/by/4.0/"
    }
  },
  "host": "petstore.swagger.wordnik.com",
  "basePath": "/api",
  "schemes": [
    "http"
  ],
  "paths": {
    "/pets": {
      "get": {
        "security": [
          {
            "basic": []
          }
        ],
        "tags": [ "Pet Operations" ],
        "operationId": "getAllPets",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "description": "The status to filter by",
            "type": "string"
          },
          {
            "name": "limit",
            "in": "query",
            "description": "The maximum number of results to return",
            "type": "integer",
						"format": "int64"
          }
        ],
        "summary": "Finds all pets in the system",
        "responses": {
          "200": {
            "description": "Pet response",
            "schema": {
              "type": "array",
              "items": {
                "$ref": "#/definitions/Pet"
              }
            }
          },
          "default": {
            "description": "Unexpected error",
            "schema": {
              "$ref": "#/definitions/Error"
            }
          }
        }
      },
      "post": {
        "security": [
          {
            "basic": []
          }
        ],
        "tags": [ "Pet Operations" ],
        "operationId": "createPet",
        "summary": "Creates a new pet",
        "consumes": ["application/x-yaml"],
        "produces": ["application/x-yaml"],
        "parameters": [
          {
            "name": "pet",
            "in": "body",
            "description": "The Pet to create",
            "required": true,
            "schema": {
              "$ref": "#/definitions/newPet"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Created Pet response",
            "schema": {
              "$ref": "#/definitions/Pet"
            }
          },
          "default": {
            "description": "Unexpected error",
            "schema": {
              "$ref": "#/definitions/Error"
            }
          }
        }
      }
    },
    "/pets/{id}": {
      "delete": {
        "security": [
          {
            "apiKey": []
          }
        ],
        "description": "Deletes the Pet by id",
        "operationId": "deletePet",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "ID of pet to delete",
            "required": true,
            "type": "integer",
            "format": "int64"
          }
        ],
        "responses": {
          "204": {
            "description": "pet deleted"
          },
          "default": {
            "description": "unexpected error",
            "schema": {
              "$ref": "#/definitions/Error"
            }
          }
        }
      },
      "get": {
        "tags": [ "Pet Operations" ],
        "operationId": "getPetById",
        "summary": "Finds the pet by id",
        "responses": {
          "200": {
            "description": "Pet response",
            "schema": {
              "$ref": "#/definitions/Pet"
            }
          },
          "default": {
            "description": "Unexpected error",
            "schema": {
              "$ref": "#/definitions/Error"
            }
          }
        }
      },
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "description": "ID of pet",
          "required": true,
          "type": "integer",
          "format": "int64"
        }
      ]
    }
  },
  "definitions": {
    "Category": {
      "id": "Category",
      "properties": {
        "id": {
          "format": "int64",
          "type": "integer"
        },
        "name": {
          "type": "string"
        }
      }
    },
    "Pet": {
      "id": "Pet",
      "properties": {
        "category": {
          "$ref": "#/definitions/Category"
        },
        "id": {
          "description": "unique identifier for the pet",
          "format": "int64",
          "maximum": 100.0,
          "minimum": 0.0,
          "type": "integer"
        },
        "name": {
          "type": "string"
        },
        "photoUrls": {
          "items": {
            "type": "string"
          },
          "type": "array"
        },
        "status": {
          "description": "pet status in the store",
          "enum": [
            "available",
            "pending",
            "sold"
          ],
          "type": "string"
        },
        "tags": {
          "items": {
            "$ref": "#/definitions/Tag"
          },
          "type": "array"
        }
      },
      "required": [
        "id",
        "name"
      ]
    },
    "newPet": {
      "anyOf": [
        {
          "$ref": "#/definitions/Pet"
        },
        {
          "required": [
            "name"
          ]
        }
      ]
    },
    "Tag": {
      "id": "Tag",
      "properties": {
        "id": {
          "format": "int64",
          "type": "integer"
        },
        "name": {
          "type": "string"
        }
      }
    },
    "Error": {
      "required": [
        "code",
        "message"
      ],
      "properties": {
        "code": {
          "type": "integer",
          "format": "int32"
        },
        "message": {
          "type": "string"
        }
      }
    }
  },
  "consumes": [
    "application/json",
    "application/xml"
  ],
  "produces": [
    "application/json",
    "application/xml",
    "text/plain",
    "text/html"
  ],
  "securityDefinitions": {
    "basic": {
      "type": "basic"
    },
    "apiKey": {
      "type": "apiKey",
      "in": "header",
      "name": "X-API-KEY"
    }
  }
}
`

const expectedExpanded = `
{  
   "produces":[  
      "application/json",
      "plain/text"
   ],
   "schemes":[  
      "https",
      "http"
   ],
   "swagger":"2.0",
   "info":{  
      "description":"Something",
      "title":"Something",
      "contact":{  
         "name":"Somebody",
         "url":"https://url.com",
         "email":"email@url.com"
      },
      "version":"v1"
   },
   "host":"security.sonusnet.com",
   "basePath":"/api",
   "paths":{  
      "/whatnot":{  
         "get":{  
            "description":"Get something",
            "responses":{  
               "200":{  
                  "description":"The something",
                  "schema":{  
                     "description":"A collection of service events",
                     "type":"object",
                     "properties":{  
                        "page":{  
                           "description":"A description of a paged result",
                           "type":"object",
                           "properties":{  
                              "page":{  
                                 "description":"the page that was requested",
                                 "type":"integer"
                              },
                              "page_items":{  
                                 "description":"the number of items per page requested",
                                 "type":"integer"
                              },
                              "pages":{  
                                 "description":"the total number of pages available",
                                 "type":"integer"
                              },
                              "total_items":{  
                                 "description":"the total number of items available",
                                 "type":"integer",
                                 "format":"int64"
                              }
                           }
                        },
                        "something":{  
                           "description":"Something",
                           "type":"object",
                           "properties":{  
                              "p1":{  
                                 "description":"A string",
                                 "type":"string"
                              },
                              "p2":{  
                                 "description":"An integer",
                                 "type":"integer"
                              }
                           }
                        }
                     }
                  }
               },
               "500":{  
                  "description":"Oops"
               }
            }
         }
      }
   },
   "definitions":{  
      "Something":{  
         "description":"A collection of service events",
         "type":"object",
         "properties":{  
            "page":{  
               "description":"A description of a paged result",
               "type":"object",
               "properties":{  
                  "page":{  
                     "description":"the page that was requested",
                     "type":"integer"
                  },
                  "page_items":{  
                     "description":"the number of items per page requested",
                     "type":"integer"
                  },
                  "pages":{  
                     "description":"the total number of pages available",
                     "type":"integer"
                  },
                  "total_items":{  
                     "description":"the total number of items available",
                     "type":"integer",
                     "format":"int64"
                  }
               }
            },
            "something":{  
               "description":"Something",
               "type":"object",
               "properties":{  
                  "p1":{  
                     "description":"A string",
                     "type":"string"
                  },
                  "p2":{  
                     "description":"An integer",
                     "type":"integer"
                  }
               }
            }
         }
      }
   }
}
`
