  Resources:

    AppSyncApi:
      Type: AWS::AppSync::GraphQLApi
      Properties:
        AuthenticationType: AMAZON_COGNITO_USER_POOLS
        Name: ${{self:custom.apiName}}
        UserPoolConfig:
          UserPoolId: !FindInMap
            - CognitoUserPoolMap
            - ${{ self:custom.stage_map.${{self:provider.stage}} }}
            - id
          AwsRegion: ${{self:provider.region}}
          DefaultAction: "ALLOW"
        AdditionalAuthenticationProviders:
          - AuthenticationType: AWS_IAM

    AppSyncSchema:
      Type: AWS::AppSync::GraphQLSchema
      Properties:
        ApiId: !GetAtt AppSyncApi.ApiId
        # camelCase for fields and PascalCase for types
        Definition: |

          schema {
            query: Query
            mutation: Mutation
            subscription: Subscription
          }

          type Query {
            getCurrentUser: User
            getSupportedFields: [Field!]!
            getCollectionSourceRows(collectionId: ID!, start: Int!, count: Int!): AWSJSON!
            getCollections(workspaceId: ID, parentId: ID): [Collection!]!
            getCollection(workspaceId: ID, collectionId: ID!): Collection!
            getGuessedLabels(collectionId: ID!): [GuessedLabel!]!
            getAllFilters(workspaceId: ID, collectionId: ID): [Filter!]!
            getGroupedFilters(workspaceId: ID, allianceId: ID, collectionId: ID): [FilterGroup!]!
            getSavedFilters(setId: ID!): [SavedFilter!]!
            geoJSON(region: String!):AWSJSON!
            getChannelId(channelName: String): ID!
            getAllAnalytics(workspaceId: ID, collectionId: ID): [ChartTypes!]!
            getGroupedAnalytics(workspaceId: ID, collectionId: ID): [AnalyticsGroup!]!
            countAll(workspaceId: ID, collectionId: ID): [CountValue!]!
            getUniqueProfiles(workspaceId: ID): Int!
            testError: Int!

            #### mvp 2.0 ####

            allAlliances: [Alliance!]!
            alliance(allianceId: ID!): Alliance!
            allianceAnalytics(allianceId: ID!, collectionId: ID): [AnalyticsGroup!]!
            eventLog(workspaceId: ID, allianceId: ID, collectionId: ID, userId: ID, offset: Int, limit: Int): CollectionEventLogPaginator!
            allWorkspaces: [Workspace!]!
            workspace(workspaceId: ID!): Workspace!

            #### facebook API ####

            fbListAudiences(allianceId:ID, collectionIds:[ID], adAccountIds: [ID]): [AudienceExtended!]!
            fbListSharedAudiences(allianceId: ID, adAccountId: ID!): [Audience!]!
            fbListAdaccounts(allianceId: ID): [AdAccount!]!
            fbListSdkAdaccounts: [AdAccount!]!
            fbListSavedSdkAdaccounts: [AdAccount!]!
            fbGetStatus(allianceId:ID): FbAccount!
            fbGetSdkStatus: FbUser!
            fbListSdkScopes: [String!]!
            fbListCountrySuggestions: [FbCountry!]!
            fbListLookalikeRatioSuggestions: [FbLookalikeRatio!]!
            fbReadAudience(allianceId: ID, audienceId: ID!): AudienceExtended!

            ## Klaviyo API
            klaviyoStatus: KlaviyoUser!
            klaviyoLists: [KlaviyoList!]!

            ## tryDelete ##

            tryDeleteWorkspace(workspaceId: ID!, acceptedConsequences:[ID]): [ConsequenceGroup!]!
            tryDeleteCollection(collectionId: ID!, acceptedConsequences:[ID]): [ConsequenceGroup!]!
            tryDeleteAlliance(allianceId: ID!, acceptedConsequences:[ID]): [ConsequenceGroup!]!
            tryDeleteAllianceCollections(allianceId: ID!, collectionIds: [ID!]!, acceptedConsequences:[ID]): [ConsequenceGroup!]!
            tryRemoveAllianceMember(allianceId: ID!, memberId: String!, acceptedConsequences:[ID]): [ConsequenceGroup!]!
            tryFbDeleteAudience(allianceId: ID, audienceId: ID!, acceptedConsequences:[ID]): [ConsequenceGroup!]!

            ## product packages ##

            productPackages: [ProductPackage!]!
            currentPackage: [UserPackage!]!


            #### Stripe billing ####

            billingInformation: BillingInformation!
            invoices: [StripeInvoice!]!
            invoice(invoiceId: ID!):AWSJSON!
            paymentMethod: StripePaymentMethod

            ####  export  ####

            exportCSV(collectionId: ID!): ExportTicket!

            #### Pelias Geo API ####

            geoAutocomplete(text: String!, size: Int, layers: String): AWSJSON!

            #### Enrichment Status & Runtime Estimation ####

            enrichmentStatus(collectionId: ID!): ProcessStatus

          }

          type Mutation {
            updateCurrentUser(input: userInput!): User!
            updateCollectionName(collectionId: ID!, newName: String!): Collection!
            mapCollection(collectionId: ID!, collectionName: String, fieldMap:[FieldPair]!): Collection!
            mergeCollection(name: String!, from: [String!]!): Collection!
            deleteCollection(collectionId: ID!, acceptedConsequences:[ID]): Collection!
            enrichFromCache(collectionId: ID!, pathPrefix: String!): String!
            createCollection(workspaceId: ID, fileName: String!): CollectionUploadUrl!
            getChannelId(channelName: String): ID!
            applyFilters(workspaceId: ID, allianceId:ID, sourceId: ID, setId:ID, filters:[FilterInput!]!):Collection!
            saveSegment(setId: ID!, name:String):Collection!
            # Experimental stuff! Use with caution!
            dropCurrentSchema: String!
            # Only backend accessible
            sendCollection(channelId: ID!, collectionId: ID!, collection: CollectionInput!): CollectionEvent!
            @aws_iam
            sendUrgentMessage(channelId: ID!, message: String, url: String): UrgentMessageEvent!
            @aws_iam
            sendTaskStatus(channelId: ID!, taskId: ID!, status: String!, progress: Int): TaskStatusEvent!
            @aws_iam
            sendAlliance(channelId: ID!, alliance: AllianceInput!): AllianceEvent!
            @aws_iam
            sendProcessStatus(channelId: ID!, collectionId: ID!, processStatus: ProcessStatusInput!): ProcessStatusEvent!
            @aws_iam

            #### mvp 2.0 ####

            createAlliance(name: String!, description: String): Alliance!
            inviteAllianceMember(allianceId: ID!, userId: String!, role: String, message: String): MemberRole!
            allianceInvitationReply(allianceId: ID!, reply: Boolean!): String!
            updateAlliance(allianceId: ID!, name: String, description: String): Alliance!
            deleteAlliance(allianceId: ID!, acceptedConsequences:[ID]): Alliance!
            setMemberRole(userId: String!, role: String!, allianceId: ID, workspaceId: ID): MemberRole!
            mergeProfilesIntoAlliance(allianceId: ID!, input: [ID!]!): Alliance!

            deleteAllianceCollections(allianceId: ID!, collectionIds: [ID!]!, acceptedConsequences:[ID]): Alliance!
            removeAllianceMember(allianceId: ID!, memberId: String!, acceptedConsequences:[ID]): MemberRole!

            createWorkspace(name: String!, description: String): Workspace!
            updateWorkspace(workspaceId: ID!, name: String, description: String): Workspace!
            deleteWorkspace(workspaceId: ID!, acceptedConsequences:[ID]): Workspace!

            #### facebook API ####

            fbGenerateAudience(allianceId: ID, collectionId: ID!, audienceName: String!, audienceDescription: String!): AudienceExtended!
            fbDeleteAudience(allianceId: ID, audienceId: ID!, acceptedConsequences:[ID]): Audience!
            fbStoreAdaccount(adAccountId: ID!, adAccountName: String, adAccountDescription: String): AdAccount!
            fbStoreSdkAdaccount(adAccountId: ID!, adAccountDescription: String): AdAccount!
            fbDeleteAdaccount(allianceId: ID, adAccountId: ID!, acceptedConsequences:[ID]): AdAccount!
            fbGenerateAndShareAudience(allianceId: ID, collectionId: ID!, audienceName: String!, audienceDescription: String!, adAccountId: ID!): AudienceExtended!
            updateFbSchema: FbSchemaUpdateStatus!
            fbGenerateLookalikeAudience(allianceId: ID, audienceName: String!, audienceDescription: String!, sourceAudienceId: ID!, audienceRatio: Float!, audienceCountryCodes: [String!]!): AudienceExtended!
            fbInitiateAudienceSharing(allianceId: ID, adAccountId: ID!, audienceId: ID!): AudienceExtended!
            fbRevokeAudienceSharingFromAdaccount(allianceId: ID, adAccountId: ID!, audienceId: ID!, acceptedConsequences:[ID]): AudienceExtended!
            fbUpdateSdkStatus(status: String!, response: FbAuthInput): FbUser!
            fbUpdateSdkAdaccounts: [AdAccount!]!

            #### klaviyo API ####
            klaviyoStatusUpdate(status: String!, privateKey: String, publicKey: String): KlaviyoUser!
            klaviyoImport(workspaceId:ID!, collectionName: String!, listIds:[ID]!): Collection!
            klaviyoExport(collectionId: ID!, listName: String!): KlaviyoExportStatus!

            #### Stripe billing ####

            updateBillingInformation(billilingInformation: BillingInformationInput): BillingInformation!
            setupIntent(stripePaymentId:String): SetupIntentResult!
            updatePaymentMethod(stripePaymentId:String!):StripePaymentMethod!
            createProductSubscription(stripePaymentId:String!, productPackageName:String!, billingCycle: String!): StripeSubscriptionResult!
            cancelProductSubscription: [UserPackage!]!
            cancelProductSchedule: [UserPackage!]!
            retryInvoice(invoiceId:String!, stripePaymentId:String): StripeSubscriptionResult!
          }

          type Subscription {
            listenOnCollectionEvents(channelId: ID!, collectionId: ID): CollectionEvent
              @aws_subscribe(mutations: ["sendCollection"])
            listenOnTaskStatusEvents(channelId: ID!): TaskStatusEvent
              @aws_subscribe(mutations: ["sendTaskStatus"])
            listenOnAllianceEvents(channelId: ID!): AllianceEvent
             @aws_subscribe(mutations: ["sendAlliance"])
            listenOnProcessStatusEvents(channelId: ID!, collectionId: ID): ProcessStatusEvent
              @aws_subscribe(mutations: ["sendProcessStatus"])
          }

          # createCollection
          type CollectionUploadUrl {
            collectionId: ID!
            uploadUrl: AWSURL!
          }


          # getCurrentUser, updateCurrentUser
          type User {
            id: ID!
            UID: String!
            email: String!
            name: String
            firstName: String
            lastName: String
            companyName: String
          }

          # getSupportedFields
          type FieldGroup{
            name: String!
            label: String!
            fields: [Field!]!
          }

          type Field {
            name: String!
            label: String!
            group: String
          }

          type GuessedLabel {
            collectionId: ID!
            columnNumber: String!
            systemFieldName: String!
            fileFieldName: String!
          }

          # getCollections, getCollection, updateCollectionName
          type Collection @aws_iam @aws_cognito_user_pools{
            id: ID!
            name: String!
            status: String!
            parentId: ID
            dateCreated: AWSDateTime!
            type: String!
            totalProfiles: Int!
            createdBy: MemberRole
          }

          type CollectionEvent @aws_iam @aws_cognito_user_pools{
            channelId: ID!
            collectionId: ID!
            collection: Collection!
          }

          input CollectionInput {
            id: ID!
            name: String
            status: String
            parentId: String
            dateCreated: AWSDateTime
            type: String
            totalProfiles: Int
          }

          input AllianceInput {
            id: ID!
            status: String
          }

          #
          type CountValue {
            id: String!
            label: String!
            value: Int!
          }

          # updateCurrentUser
          input userInput {
            firstName: String
            lastName: String
            companyName: String
          }

          # mapCollection
          input FieldPair {
            index: Int! # previously incomingFieldName: String
            value: String! # previously systemFieldName: String
          }

          # getAllFilters
          type LocationFilter {
            id: ID!
            minDistance: Int
            maxDistance: Int
            radiusPlaceholder: String
            searchPlaceholder: String
            searchInputDelay: Int
            searchLayers: String
            searchSize: Int
          }

          # getAllFilters
          type Range {
            id: ID!
            name: String!
            placeholder: String
            min: Int
            max: Int
          }

          # getAllFilters
          type MultiSelect {
            id: ID!
            name: String!
            label: String!
            value: String!
          }

          # getAllFilters
          type Filter {
            id: ID!
            type: String!
            label: String!
            options: [FilterOptions!]
          }

          input FilterInput {
            id: ID!
            values:[String!]!
          }

          type SavedFilter {
            id: ID!
            type: String!
            values: [String!]!
          }


          # getAllFilters
          union FilterOptions = Range | MultiSelect | LocationFilter

          # realtime communication subscription types
          interface ChannelEvent @aws_iam @aws_cognito_user_pools {
            channelId: ID!
          }

          type UrgentMessageEvent implements ChannelEvent @aws_iam @aws_cognito_user_pools {
            channelId: ID!
            message: String!
            url: String
          }

          type TaskStatusEvent implements ChannelEvent @aws_iam @aws_cognito_user_pools {
            channelId: ID!
            taskId: ID!
            status: String!
            # Optional 0..100
            progress: Int!
          }

          union ChannelEvents = UrgentMessageEvent | TaskStatusEvent

          # Analytics query stuff
          type DataItem {
            id: ID!
            label: String!
            value: Float!
          }

          type TreeMapItem {
            id: ID!
            parent: ID!
            label: String!
            value: Float!
          }

          type CalendarItem {
            id: ID!
            day: String!
            value: Float!
          }

          type InfoItem {
            id: ID!
            name: String!
            description: String!
          }

          type InfoTab {
            id: ID!
            name: String!
            items: [InfoItem!]!
          }

          type DataGroup {
            id: ID!
            group: String!
            items: [DataItem!]!
          }

          type MultiLine {
            id: ID!
            label: String!
            graph: [DataItem!]!
          }

          type PieChart {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [DataItem!]!
          }

          type BarChart {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [DataItem!]!
          }

          type AreaChart {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [DataItem!]!
          }

          type StackChart {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [DataGroup!]!
            keys: [String!]!
            maxValue: Float!
          }

          type GroupChart {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [DataGroup!]!
            keys: [String!]!
            maxValue: Float!
          }

          type LineChart {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [MultiLine!]!
            curve: String!
            maxValue: Float!
          }

          type TreeMap {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [TreeMapItem!]!
          }

          type CalendarChart {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [CalendarItem!]!
          }

          type Choropleth {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [DataItem!]!
            region: String!
            projection: String!
          }

          type InfoTabs {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [InfoTab!]!
          }

          type RadarChart {
            id: ID!
            type: String!
            label: String!
            options: AWSJSON
            description: String
            data: [DataGroup!]!
            keys: [String!]!
            maxValue: Float!
          }

          type ParetoChart {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON
            data: [DataItem!]!
          }
          
          type Table {
            id: ID!
            type: String!
            label: String!
            description: String
            options: AWSJSON!
            data: AWSJSON!
          }
          
          type TableColumn {
            id: ID!
            key: String!
            label: String!
            type: String!
            range: [Float!]
            valueFormat: String!
          }

          union ChartTypes = PieChart | BarChart | AreaChart | StackChart | GroupChart | TreeMap | CalendarChart | LineChart | Choropleth | InfoTabs | RadarChart | ParetoChart | Table

          type AnalyticsGroup {
            id:ID!
            name: String!
            description: String!
            charts: [ChartTypes!]!
          }

          type FilterGroup {
            id:ID!
            name: String!
            description: String!
            filters: [Filter!]!
          }
          
          
          ###### mvp 2.0 ###

          type MemberRole {
            id: ID!
            name: String!
            company: String
            role: String
            email: String!
            me: Boolean!
            pending: Boolean
          }

          type Alliance @aws_iam @aws_cognito_user_pools{
            id: ID!
            name: String!
            description: String!
            status: String!
            dateCreated: AWSDateTime!
            lastUpdated: AWSDateTime!
            createdBy: MemberRole!
            type: String
            totalProfiles: Int!
            members: [MemberRole!]!
            segments: [Collection!]!
            collections: [Collection!]!
          }


          type Workspace @aws_iam @aws_cognito_user_pools{
            id: ID!
            name: String!
            description: String
            status: String!
            dateCreated: AWSDateTime!
            lastUpdated: AWSDateTime!
            createdBy: MemberRole
            type: String
            totalProfiles: Int!
            ## members: [MemberRole!]
            ## segments: [Collection!]
            collections: [Collection!]!
          }

          type AllianceEvent @aws_iam @aws_cognito_user_pools{
            channelId: ID!
            alliance: Alliance!
          }

          type WorkspaceEvent @aws_iam @aws_cognito_user_pools{
            channelId: ID!
            workspace: Workspace!
          }

          type CollectionEventLogItem @aws_iam @aws_cognito_user_pools{
            id: ID!
            collectionId: ID
            member: MemberRole!
            eventType: String!
            eventDesc: String!
            timeStamp: AWSDateTime!
          }

          type CollectionEventLogPaginator @aws_iam @aws_cognito_user_pools{
            items: [CollectionEventLogItem!]!
            offset: Int!
            length: Int!
          }

          type Company {
            name: String!
            members: [User!]!
          }

          type AdAccount {
            id: ID!
            name: String!
            description: String!
            status: Int!
            businessId: String
            businessName: String
          }

          type AdAccountExtended {
            id: ID!
            adaccountId: ID!
            name: String!
            description: String!
            status: Int!
            businessId: String
            businessName: String
            sharedStatus: String!
          }

          type AudienceExtended {
            id: ID!
            name: String!
            description: String!
            size: Int!
            collectionId: Int!
            sharedWith: [AdAccountExtended!]!
            ratio: FbLookalikeRatio
            countries:[FbCountry!]!
            parentId: ID
            source: AudienceSource
            timestampCreated: AWSDateTime!
            timestampUpdated: AWSDateTime!
          }

          type AudienceSource {
            cawType: String!
            cawSchema: String!
          }

          type Audience {
            id: ID!
            name: String!
            description: String!
            size: Int!
            collectionId: Int
          }

          type FbAccount {
            status: String!
          }

          type FbUser {
            status: String!
            id: ID
            grantedScopes: [String!]!
          }

          type FbSchemaUpdateStatus {
            status: String!
          }

          type FbCountry {
            id: String!
            name: String!
          }

          type FbLookalikeRatio {
            id: Float!
            name: String!
          }

          input FbAuthInput {
            accessToken: String!
            data_access_expiration_time: Int
            expiresIn: Int
            grantedScopes: String!
            graphDomain: String
            signedRequest: String
            userID: String!
          }

          type ConsequenceGroup {
            id: ID!
            type: String!
            description: String!
            count: Int!
            items: [ID!]!
            accepted: [ID!]!
          }

          type KlaviyoUser {
            status: String!
          }

          type KlaviyoExportStatus {
            status: String!
            profileCount: Int!
          }

          type KlaviyoList {
            timestampUpdated: String!
            personCount: Int!
            name: String!
            timestampCreated: String!
            listType: String!
            folder: String
            id: ID!
          }

          type ProductPrice {
            price: Float!
            campaignPrice: Float
            billingCycle: String!
          }

          type ProductPackage {
            name: String!
            description: String!
            campaignDescription: String
            campaignCode: String
            prices: [ProductPrice!]!
            quotas: [UserPackageQuota!]!
          }

          type UserPackageQuota {
            id: ID!
            name: String!
            description: String!
            limit: Int!
            current: Int!
          }

          type UserPackage {
            id: ID!
            name: String!
            description: String!
            status: String!
            paymentStatus: String!
            paymentErrorMessage: String
            price: Float!
            billingCycle: String!
            cancelAtPeriodEnd: Boolean!
            nextPayment: AWSDate
            quotas: [UserPackageQuota!]!
          }

          type BillingInformation {
            phone: String!
            email: String!
            name: String!
            company: String!
            vat: String!
            line1: String!
            line2: String!
            city: String!
            state: String!
            country: String!
            postalCode: String!
          }

          input BillingInformationInput {
            phone: String
            email: String
            name: String
            company: String
            vat: String
            line1: String
            line2: String
            city: String
            state: String
            country: String
            postalCode: String
          }

          type StripeInvoice {
            id: ID!
            created: AWSDate!
            number: String!
            pdfUrl: String!
            status: String!
            paid: Boolean!
          }

          type StripePaymentMethod {
            id: ID!
            brand: String!
            country: String!
            expMonth: String!
            expYear: String!
            lastFour: String!
            created: AWSDateTime!
          }

          type StripeSubscriptionResult {
            subscriptionStatus: String!
            paymentIntentStatus: String!
            invoiceId: String!
            intentType: String!
            clientSecret: String!
            paymentIntentError: String
            paymentMethodId: String!
          }

          type SetupIntentResult {
            status: String!
            clientSecret: String!
            lastError: String
          }

          type ExportTicket {
            profileCount: Int!
            downloadUrl: String
          }

          input ProcessStatusInput {
            status: String!
            tasksCompleted: Int!
            tasksTotal: Int!
            estimatedTimeRemaining: Float!
          }

          type ProcessStatus @aws_iam @aws_cognito_user_pools{
            status: String!
            tasksCompleted: Int!
            tasksTotal: Int!
            estimatedTimeRemaining: Float!
          }

          type ProcessStatusEvent @aws_iam @aws_cognito_user_pools{
            channelId: ID!
            collectionId: ID!
            processStatus: ProcessStatus!
          }
