{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}

module Namespaces.Sophisticated where

import Data.Morpheus.Server.CodeGen.Internal
import Data.Morpheus.Server.Types
import Globals.GQLScalars (TestScalar)

data TestEnum
  = TestEnumEnumA
  | TestEnumEnumB
  | TestEnumEnumC
  deriving (Generic, Show)

instance GQLType TestEnum where
  type KIND TestEnum = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "TestEnum"}
      <> enumDirective "TestEnumEnumA" Describe {text = "\n  enumValue Description: EnumA\n  "}
      <> enumDirective "TestEnumEnumB" Deprecated {reason = Just "test deprecation enumValue"}
      <> enumDirective "TestEnumEnumC" Deprecated {reason = Nothing}
      <> enumDirective "TestEnumEnumC" Describe {text = "\n  enumValue Description: EnumC\n  "}
      <> typeDirective Describe {text = "\ntype Description: TestEnum\n\nsome random enums for test\n"}

data CollidingEnum
  = CollidingEnumEnumA
  | CollidingEnumEnumB
  | CollidingEnumEnumC
  deriving (Generic, Show)

instance GQLType CollidingEnum where
  type KIND CollidingEnum = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "CollidingEnum"}
      <> enumDirective "CollidingEnumEnumA" Describe {text = "\n  enumValue Description: EnumA\n  "}
      <> enumDirective "CollidingEnumEnumB" Deprecated {reason = Just "test deprecation enumValue"}
      <> enumDirective "CollidingEnumEnumC" Deprecated {reason = Nothing}
      <> enumDirective "CollidingEnumEnumC" Describe {text = "\n  enumValue Description: EnumC\n  "}

newtype NestedInputObject = NestedInputObject
  { nestedInputObjectFieldTestID :: ID
  }
  deriving (Generic, Show)

instance GQLType NestedInputObject where
  type KIND NestedInputObject = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "NestedInputObject"}

data TestInputObject = TestInputObject
  { testInputObjectFieldTestScalar :: TestScalar,
    testInputObjectFieldNestedInputObject :: [Maybe NestedInputObject]
  }
  deriving (Generic, Show)

instance GQLType TestInputObject where
  type KIND TestInputObject = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "TestInputObject"}

data Coordinates = Coordinates
  { coordinatesLatitude :: TestScalar,
    coordinatesLongitude :: Int
  }
  deriving (Generic, Show)

instance GQLType Coordinates where
  type KIND Coordinates = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "Coordinates"}
      <> fieldDirective "coordinatesLatitude" Describe {text = "\n  inputValue Description: latitude\n  "}
      <> fieldDirective "coordinatesLongitude" Describe {text = "\n  inputValue Description: longitude\n  some random inputValue details\n  "}
      <> typeDirective Describe {text = "\ntype Description: Coordinates\n\nsome random text\n"}
      <> fieldDirective "coordinatesLongitude" DefaultValue {defaultValue = Scalar (Int 4)}

data Address m = Address
  { addressCity :: m Text,
    addressStreet :: AddressStreetArgs -> m (Maybe [Maybe [[[Text]]]]),
    addressHouseNumber :: m Int
  }
  deriving (Generic)

instance (Typeable m) => GQLType (Address m) where
  type KIND (Address m) = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "Address"}
      <> fieldDirective "addressCity" Deprecated {reason = Just "test deprecation field with reason"}
      <> fieldDirective "addressCity" Describe {text = "\n  field Description: city\n  "}
      <> fieldDirective "addressStreet" Deprecated {reason = Nothing}
      <> typeDirective Describe {text = "\ntype Description:\n\n  Address\n"}

data AddressStreetArgs = AddressStreetArgs
  { addressStreetArgsArgInputObject :: TestInputObject,
    addressStreetArgsArgMaybeString :: Maybe Text
  }
  deriving (Generic, Show)

instance GQLType AddressStreetArgs where
  type KIND AddressStreetArgs = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "AddressStreetArgs"}
      <> fieldDirective "addressStreetArgsArgInputObject" Describe {text = "\n    argument Description: inputObject\n    "}

data TestUnion m
  = TestUnionUser (m (User m))
  | TestUnionAddress (m (Address m))
  deriving (Generic)

instance (Typeable m) => GQLType (TestUnion m) where
  type KIND (TestUnion m) = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "TestUnion"}
      <> typeDirective Describe {text = "\ntype Description: TestUnion\n\nsome random text for union type\n"}

newtype InterfacePerson m = InterfacePerson
  { interfacePersonName :: m (Maybe Text)
  }
  deriving (Generic)

instance (Typeable m) => GQLType (InterfacePerson m) where
  type KIND (InterfacePerson m) = TYPE
  directives _ =
    typeDirective Rename {newName = "Person"}
      <> typeDirective DropNamespace {dropNamespace = "InterfacePerson"}

type Person m = TypeGuard (InterfacePerson m) (User m)

data User m = User
  { userName :: m Text,
    userEmail :: m Text,
    userAddress :: UserAddressArgs -> m (Address m),
    userOffice :: UserOfficeArgs -> m (Address m),
    userFriend :: m (Maybe (User m))
  }
  deriving (Generic)

instance (Typeable m) => GQLType (User m) where
  type KIND (User m) = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "User"}
      <> fieldDirective "userName" Describe {text = "\n  field description: name\n  "}
      <> fieldDirective "userEmail" Describe {text = "\n  field description: email\n  "}
      <> typeDirective Describe {text = "\nUser\n\nMultilineDescription\n\nTest\n"}

data UserAddressArgs = UserAddressArgs
  { userAddressArgsCoordinates :: Coordinates,
    userAddressArgsComment :: Maybe Text
  }
  deriving (Generic, Show)

instance GQLType UserAddressArgs where
  type KIND UserAddressArgs = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "UserAddressArgs"}

data UserOfficeArgs = UserOfficeArgs
  { userOfficeArgsZipCode :: Maybe [Int],
    userOfficeArgsCityID :: TestEnum
  }
  deriving (Generic, Show)

instance GQLType UserOfficeArgs where
  type KIND UserOfficeArgs = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "UserOfficeArgs"}

data Query m = Query
  { queryUser :: m (User m),
    queryTestUnion :: m (Maybe (TestUnion m)),
    queryPerson :: m (Person m),
    queryTestEnum :: Arg "enum" CollidingEnum -> m [CollidingEnum]
  }
  deriving (Generic)

instance (Typeable m) => GQLType (Query m) where
  type KIND (Query m) = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "Query"}

newtype Mutation m = Mutation
  { mutationCreateUser :: MutationCreateUserArgs -> m (User m)
  }
  deriving (Generic)

instance (Typeable m) => GQLType (Mutation m) where
  type KIND (Mutation m) = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "Mutation"}

data MutationCreateUserArgs = MutationCreateUserArgs
  { mutationCreateUserArgsUserID :: Text,
    mutationCreateUserArgsUserName :: Maybe Text
  }
  deriving (Generic, Show)

instance GQLType MutationCreateUserArgs where
  type KIND MutationCreateUserArgs = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "MutationCreateUserArgs"}

data Subscription m = Subscription
  { subscriptionNewUser :: m (User m),
    subscriptionNewAddress :: m (Address m)
  }
  deriving (Generic)

instance (Typeable m) => GQLType (Subscription m) where
  type KIND (Subscription m) = TYPE
  directives _ =
    typeDirective DropNamespace {dropNamespace = "Subscription"}
