(ns ctia.entity.malware
  (:require
   [ctia.domain.entities :refer [default-realize-fn]]
   [ctia.entity.feedback.graphql-schemas :as feedback]
   [ctia.entity.relationship.graphql-schemas :as relationship]
   [ctia.http.routes.common :as routes.common]
   [ctia.http.routes.crud :refer [services->entity-crud-routes]]
   [ctia.schemas.core :refer [APIHandlerServices def-acl-schema def-stored-schema]]
   [ctia.schemas.graphql.flanders :as flanders]
   [ctia.schemas.graphql.helpers :as g]
   [ctia.schemas.graphql.ownership :as go]
   [ctia.schemas.graphql.pagination :as pagination]
   [ctia.schemas.graphql.sorting :as graphql-sorting]
   [ctia.schemas.sorting :as sorting]
   [ctia.stores.es.mapping :as em]
   [ctia.stores.es.store :refer [def-es-store]]
   [ctim.schemas.malware :as malware]
   [flanders.utils :as fu]
   [schema-tools.core :as st]
   [schema.core :as s]))

(def-acl-schema Malware
  malware/Malware
  "malware")

(def-acl-schema PartialMalware
  (fu/optionalize-all malware/Malware)
  "partial-malware")

(s/defschema PartialMalwareList
  [PartialMalware])

(def-acl-schema NewMalware
  malware/NewMalware
  "new-malware")

(def-stored-schema StoredMalware Malware)

(s/defschema PartialStoredMalware
  (st/optional-keys-schema StoredMalware))

(def realize-malware
  (default-realize-fn "malware" NewMalware StoredMalware))

(def malware-mapping
  {"malware"
   {:dynamic false
    :properties
    (merge
     em/base-entity-mapping
     em/sourcable-entity-mapping
     em/describable-entity-mapping
     em/stored-entity-mapping
     {:labels            em/searchable-token
      :kill_chain_phases em/kill-chain-phase
      :x_mitre_aliases   em/searchable-token
      :abstraction_level em/token})}})

(def-es-store MalwareStore :malware StoredMalware PartialStoredMalware)

(def malware-fields sorting/default-entity-sort-fields)

(def malware-sort-fields
  (apply s/enum malware-fields))

(s/defschema MalwareFieldsParam
  {(s/optional-key :fields) [malware-sort-fields]})

(s/defschema MalwareSearchParams
  (st/merge
   routes.common/PagingParams
   routes.common/BaseEntityFilterParams
   routes.common/SourcableEntityFilterParams
   routes.common/SearchableEntityParams
   MalwareFieldsParam
   (st/optional-keys
    {:labels                            s/Str
     :kill_chain_phases.kill_chain_name s/Str
     :kill_chain_phases.phase_name      s/Str
     :sort_by                           malware-sort-fields})))

(def malware-histogram-fields
  [:timestamp])

(def malware-enumerable-fields
  [:source
   :labels])

(s/defschema MalwareGetParams MalwareFieldsParam)

(s/defschema MalwareByExternalIdQueryParams
  (st/merge
   routes.common/PagingParams
   MalwareFieldsParam))

(def capabilities
  #{:create-malware
    :read-malware
    :delete-malware
    :search-malware})

(def MalwareType
  (let [{:keys [fields name description]}
        (flanders/->graphql
         (fu/optionalize-all malware/Malware)
         {})]
    (g/new-object
     name
     description
     []
     (merge fields
            feedback/feedback-connection-field
            relationship/relatable-entity-fields
            go/graphql-ownership-fields))))

(def malware-order-arg
  (graphql-sorting/order-by-arg
   "MalwareOrder"
   "malwares"
   (into {}
         (map (juxt graphql-sorting/sorting-kw->enum-name name)
              malware-fields))))

(def MalwareConnectionType
  (pagination/new-connection MalwareType))

(def searchable-fields
  #{:id
    :source
    :description
    :kill_chain_phases.kill_chain_name
    :kill_chain_phases.phase_name
    :labels
    :short_description
    :title
    :x_mitre_aliases})

(s/defn malware-routes [services :- APIHandlerServices]
  (services->entity-crud-routes
   services
   {:entity                   :malware
    :new-schema               NewMalware
    :entity-schema            Malware
    :get-schema               PartialMalware
    :get-params               MalwareGetParams
    :list-schema              PartialMalwareList
    :search-schema            PartialMalwareList
    :external-id-q-params     MalwareByExternalIdQueryParams
    :search-q-params          MalwareSearchParams
    :new-spec                 :new-malware/map
    :realize-fn               realize-malware
    :get-capabilities         :read-malware
    :post-capabilities        :create-malware
    :put-capabilities         :create-malware
    :delete-capabilities      :delete-malware
    :search-capabilities      :search-malware
    :external-id-capabilities :read-malware
    :can-aggregate?           true
    :histogram-fields         malware-histogram-fields
    :enumerable-fields        malware-enumerable-fields}))

(def malware-entity
  {:route-context         "/malware"
   :tags                  ["Malware"]
   :entity                :malware
   :plural                :malwares
   :new-spec              :new-malware/map
   :schema                Malware
   :partial-schema        PartialMalware
   :partial-list-schema   PartialMalwareList
   :new-schema            NewMalware
   :stored-schema         StoredMalware
   :partial-stored-schema PartialStoredMalware
   :realize-fn            realize-malware
   :es-store              ->MalwareStore
   :es-mapping            malware-mapping
   :services->routes      (routes.common/reloadable-function malware-routes)
   :capabilities          capabilities
   :fields                malware-fields
   :sort-fields           malware-fields
   :searchable-fields     searchable-fields})

(ns ctia.entity.malware
  (:require
   [ctia.domain.entities :refer [default-realize-fn]]
   [ctia.entity.feedback.graphql-schemas :as feedback]
   [ctia.entity.relationship.graphql-schemas :as relationship]
   [ctia.http.routes.common :as routes.common]
   [ctia.http.routes.crud :refer [services->entity-crud-routes]]
   [ctia.schemas.core :refer [APIHandlerServices def-acl-schema def-stored-schema]]
   [ctia.schemas.graphql.flanders :as flanders]
   [ctia.schemas.graphql.helpers :as g]
   [ctia.schemas.graphql.ownership :as go]
   [ctia.schemas.graphql.pagination :as pagination]
   [ctia.schemas.graphql.sorting :as graphql-sorting]
   [ctia.schemas.sorting :as sorting]
   [ctia.stores.es.mapping :as em]
   [ctia.stores.es.store :refer [def-es-store]]
   [ctim.schemas.malware :as malware]
   [flanders.utils :as fu]
   [schema-tools.core :as st]
   [schema.core :as s]))

(def-acl-schema Malware
  malware/Malware
  "malware")

(def-acl-schema PartialMalware
  (fu/optionalize-all malware/Malware)
  "partial-malware")

(s/defschema PartialMalwareList
  [PartialMalware])

(def-acl-schema NewMalware
  malware/NewMalware
  "new-malware")

(def-stored-schema StoredMalware Malware)

(s/defschema PartialStoredMalware
  (st/optional-keys-schema StoredMalware))

(def realize-malware
  (default-realize-fn "malware" NewMalware StoredMalware))

(def malware-mapping
  {"malware"
   {:dynamic false
    :properties
    (merge
     em/base-entity-mapping
     em/sourcable-entity-mapping
     em/describable-entity-mapping
     em/stored-entity-mapping
     {:labels            em/searchable-token
      :kill_chain_phases em/kill-chain-phase
      :x_mitre_aliases   em/searchable-token
      :abstraction_level em/token})}})

(def-es-store MalwareStore :malware StoredMalware PartialStoredMalware)

(def malware-fields sorting/default-entity-sort-fields)

(def malware-sort-fields
  (apply s/enum malware-fields))

(s/defschema MalwareFieldsParam
  {(s/optional-key :fields) [malware-sort-fields]})

(s/defschema MalwareSearchParams
  (st/merge
   routes.common/PagingParams
   routes.common/BaseEntityFilterParams
   routes.common/SourcableEntityFilterParams
   routes.common/SearchableEntityParams
   MalwareFieldsParam
   (st/optional-keys
    {:labels                            s/Str
     :kill_chain_phases.kill_chain_name s/Str
     :kill_chain_phases.phase_name      s/Str
     :sort_by                           malware-sort-fields})))

(def malware-histogram-fields
  [:timestamp])

(def malware-enumerable-fields
  [:source
   :labels])

(s/defschema MalwareGetParams MalwareFieldsParam)

(s/defschema MalwareByExternalIdQueryParams
  (st/merge
   routes.common/PagingParams
   MalwareFieldsParam))

(def capabilities
  #{:create-malware
    :read-malware
    :delete-malware
    :search-malware})

(def MalwareType
  (let [{:keys [fields name description]}
        (flanders/->graphql
         (fu/optionalize-all malware/Malware)
         {})]
    (g/new-object
     name
     description
     []
     (merge fields
            feedback/feedback-connection-field
            relationship/relatable-entity-fields
            go/graphql-ownership-fields))))

(def malware-order-arg
  (graphql-sorting/order-by-arg
   "MalwareOrder"
   "malwares"
   (into {}
         (map (juxt graphql-sorting/sorting-kw->enum-name name)
              malware-fields))))

(def MalwareConnectionType
  (pagination/new-connection MalwareType))

(def searchable-fields
  #{:id
    :source
    :description
    :kill_chain_phases.kill_chain_name
    :kill_chain_phases.phase_name
    :labels
    :short_description
    :title
    :x_mitre_aliases})

(s/defn malware-routes [services :- APIHandlerServices]
  (services->entity-crud-routes
   services
   {:entity                   :malware
    :new-schema               NewMalware
    :entity-schema            Malware
    :get-schema               PartialMalware
    :get-params               MalwareGetParams
    :list-schema              PartialMalwareList
    :search-schema            PartialMalwareList
    :external-id-q-params     MalwareByExternalIdQueryParams
    :search-q-params          MalwareSearchParams
    :new-spec                 :new-malware/map
    :realize-fn               realize-malware
    :get-capabilities         :read-malware
    :post-capabilities        :create-malware
    :put-capabilities         :create-malware
    :delete-capabilities      :delete-malware
    :search-capabilities      :search-malware
    :external-id-capabilities :read-malware
    :can-aggregate?           true
    :histogram-fields         malware-histogram-fields
    :enumerable-fields        malware-enumerable-fields}))

(def malware-entity
  {:route-context         "/malware"
   :tags                  ["Malware"]
   :entity                :malware
   :plural                :malwares
   :new-spec              :new-malware/map
   :schema                Malware
   :partial-schema        PartialMalware
   :partial-list-schema   PartialMalwareList
   :new-schema            NewMalware
   :stored-schema         StoredMalware
   :partial-stored-schema PartialStoredMalware
   :realize-fn            realize-malware
   :es-store              ->MalwareStore
   :es-mapping            malware-mapping
   :services->routes      (routes.common/reloadable-function malware-routes)
   :capabilities          capabilities
   :fields                malware-fields
   :sort-fields           malware-fields
   :searchable-fields     searchable-fields})
