// Available variables:
// - Machine
// - interpret
// - assign
// - send
// - sendParent
// - spawn
// - raise
// - actions
// - XState (all XState exports)

const mapInviteTypeToConnectionType = inviteType => {
  switch (inviteType) {
    case "COLLEAGUE":
      return "COLLEAGUE";
    case "ORGANIZATION_CODE": // Legacy type from <=3.X
    case "PATIENT": // Legacy type from <=3.X
    case "SECURE_MESSAGE":
      return "SECURE_MESSAGE";
    case "UNKNOWN":
    default:
      console.error(`Unexpected inviteType ${inviteType}`);
      return "SECURE_MESSAGE";
  }
};

const associateInvite = (
  accountCreationIntent,
  accountInviteClientID,
  inviteCode
) =>
  new Promise(resolve =>
    setTimeout(() => {
      resolve({
        data: {
          associateInvite: {
            confirmationScreen: {
              body: "",
              buttonText: "Continue",
              entityProfile: {
                url: "https://invite.spruce-dev.com/e/18M23V27KJ800"
              },
              imageURL:
                "https://msg-media.spruce-dev.com/media/e867db5a-ba30-9dba-7cc0-38cb-f9887032?mimetype=image%2Fpng",
              photoStyle: "BORDERED_CIRCLE",
              title: "You're joining Sara Brown, PsyD"
            },
            errorCode: null,
            errorMessage: null,
            // inviteType: "ORGANIZATION_CODE",
            // inviteType: "SECURE_MESSAGE",
            inviteType: "COLLEAGUE",
            phoneNumberVerificationText: null,
            values: [
              {
                key: "client_data",
                value:
                  '{"patient_invite":{"greeting":{"title":"You\'re Joining Sara Brown, PsyD","message":"Let\'s create your account so you can start securely messaging with Sara Brown, PsyD.","button_text":"Get Started"},"org_id":"entity_18M23V27KJ800","org_name":"Sara Brown, PsyD"},"practice_invite":{"greeting":{"title":"You\'re Joining Sara Brown, PsyD","message":"Let\'s create your account so you can start securely messaging with Sara Brown, PsyD.","button_text":"Get Started"},"org_id":"entity_18M23V27KJ800","org_name":"Sara Brown, PsyD","join_as_teammate":false}}'
              },
              {
                key: "invite_type",
                value: "ORGANIZATION_CODE"
              },
              {
                key: "$desktop_url",
                value: "https://app.spruce-dev.com/?invite=sara-brown"
              },
              {
                key: "invite_token",
                value: "sara-brown"
              }
            ],
            verifyPhoneNumber: true
          }
        }
      });
    }, 1000)
  );

const verifyPhoneNumber = phoneNumber =>
  Promise.resolve({
    data: {
      verifyPhoneNumberForAccountCreation: {
        errorCode: null,
        errorMessage: null,
        message: "A verification code has been sent to (630) 915-9986",
        token: "-XPIFGaWcwroulS8i_5zqQ"
      }
    }
  });

// const checkVerificationCode = verificationCode =>
//   Promise.resolve({
//     data: {
//       checkVerificationCode: {
//         account: null,
//         errorCode: "CODE_EXPIRED",
//         errorMessage:
//           "The entered code has expired. Please request a new code.",
//         inviteType: null,
//         success: false,
//         verifiedEntityInfo: null
//       }
//     }
//   });

const checkVerificationCode = verificationCode =>
  Promise.resolve({
    data: {
      checkVerificationCode: {
        account: null,
        confirmationScreen: null,
        errorCode: null,
        errorMessage: null,
        inviteType: null,
        success: true,
        verifiedEntityInfo: null
      }
    }
  });

const detectPresenceOfInviteCode = () =>
  new Promise(resolve =>
    setTimeout(() => {
      resolve("sara-brown");
    }, 200)
  );

const fetchMachine = Machine({
  id: "account-creation",
  initial: "initialize",
  context: {
    inviteCode: "",
    accountCreationIntent: "PROVIDER",
    connectionType: "",
    phoneVerificationToken: "",
    inviteConfirmationScreen: null,
    accountInviteClientID: "",
    firstName: "",
    lastName: "",
    shortTitle: "",
    organizationName: "",
    dob: {},
    gender: "",
    genderDetail: "",
    email: "",
    password: "",
    errorMessage: ""
  },
  states: {
    initialize: {
      initial: "detectPresenceOfInviteCode",
      states: {
        detectPresenceOfInviteCode: {
          invoke: {
            id: "detectPresenceOfInviteCode",
            src: (context, event) => detectPresenceOfInviteCode(),
            onDone: {
              target: "callingAssociateInvite",
              internal: true,
              actions: assign({
                inviteCode: (context, event) => event.data
              })
            },
            onError: {
              target: "#choosePatientOrProvider",
              actions: assign({
                error: (context, event) => {
                  // In practice, there will never be an error, since we're simply checking the query params for the token and that can't fail
                  console.error(event);
                }
              })
            }
          }
        },
        callingAssociateInvite: {
          invoke: {
            id: "associateInvite",
            src: (context, event) =>
              associateInvite(
                context.accountCreationIntent,
                context.accountInviteClientID,
                context.inviteCode
              ),
            onDone: [
              {
                target: "#choosePatientOrProvider",
                actions: assign({
                  connectionType: (context, event) =>
                    mapInviteTypeToConnectionType(
                      event.data.data.associateInvite.inviteType
                    )
                }),
                cond: (context, event) => {
                  if (
                    !event ||
                    !event.data ||
                    !event.data.data ||
                    !event.data.data.associateInvite ||
                    !event.data.data.associateInvite.inviteType
                  ) {
                    return false;
                  }
                  const connectionType = mapInviteTypeToConnectionType(
                    event.data.data.associateInvite.inviteType
                  );
                  switch (connectionType) {
                    case "SECURE_MESSAGE":
                      return true;
                    case "COLLEAGUE":
                      return false;
                  }
                }
              },
              {
                target: "#confirmPracticeBeingJoined",
                actions: assign({
                  connectionType: (context, event) =>
                    mapInviteTypeToConnectionType(
                      event.data.data.associateInvite.inviteType
                    ),
                  confirmationScreen: (context, event) =>
                    mapInviteTypeToConnectionType(
                      event.data.data.associateInvite.confirmationScreen
                    )
                }),
                cond: (context, event) => {
                  if (
                    !event ||
                    !event.data ||
                    !event.data.data ||
                    !event.data.data.associateInvite ||
                    !event.data.data.associateInvite.inviteType
                  ) {
                    return false;
                  }
                  const connectionType = mapInviteTypeToConnectionType(
                    event.data.data.associateInvite.inviteType
                  );
                  switch (connectionType) {
                    case "SECURE_MESSAGE":
                      return false;
                    case "COLLEAGUE":
                      return true;
                  }
                }
              }
            ],
            onError: {
              target: "#choosePatientOrProvider",
              actions: assign({
                error: (context, event) => {
                  console.error(event);
                }
              })
            }
          }
        }
      }
    },
    choosePatientOrProvider: {
      id: "choosePatientOrProvider",
      on: {
        PATIENT: {
          target: "enterPhoneNumber",
          actions: "markAsPatient"
        },
        PROVIDER: [
          {
            target: "enterPhoneNumber",
            actions: "markAsProvider",
            cond: context => context.inviteType === "COLLEAGUE"
          },
          {
            target: "chooseJoinExistingClinicOrCreateNewClinic",
            actions: "markAsProvider"
          }
        ]
      }
    },
    chooseJoinExistingClinicOrCreateNewClinic: {
      id: "chooseJoinExistingClinicOrCreateNewClinic",
      on: {
        JOIN_EXISTING: {
          target: "joinExistingClinic",
          actions: "markAsPatient"
        },
        CREATE_NEW: {
          target: "enterPhoneNumber",
          actions: "markAsProvider"
        }
      }
    },
    // The joinExistingClinic state is just going to explain how to join an existing practice and link to the help center
    joinExistingClinic: {
      on: {
        BACK: {
          target: "chooseJoinExistingClinicOrCreateNewClinic"
        }
      }
    },
    enterPhoneNumber: {
      id: "enterPhoneNumber",
      initial: "awaitPhoneNumberEntry",
      states: {
        awaitPhoneNumberEntry: {
          on: {
            CHANGE: {
              actions: assign({
                phoneNumber: (ctx, e) => e.data
              })
            },
            SUBMIT: { target: "sendingPhoneVerificationCode", internal: true },
            BACK: "#choosePatientOrProvider"
          }
        },
        sendingPhoneVerificationCode: {
          invoke: {
            id: "verifyPhoneNumber",
            src: (context, event) => verifyPhoneNumber(context.phoneNumber),
            onDone: {
              target: "#enterPhoneVerificationCode",
              internal: false
            },
            onError: {
              target: "error",
              actions: assign({
                error: (context, event) => {
                  console.error(event);
                }
              })
            }
          }
        },
        error: { type: "final" }
      }
    },
    enterPhoneVerificationCode: {
      id: "enterPhoneVerificationCode",
      initial: "awaitVerificationCodeEntry",
      states: {
        awaitVerificationCodeEntry: {
          on: {
            CHANGE: {
              actions: assign({
                verificationCode: (ctx, e) => e.data
              })
            },
            SUBMIT: {
              target: "verifyingCode",
              internal: true
            }
          }
        },
        verifyingCode: {
          invoke: {
            id: "checkVerificationCode",
            src: (context, event) =>
              checkVerificationCode(context.verificationCode),
            onDone: [
              {
                target: "awaitVerificationCodeEntry",
                internal: true,
                actions: assign({
                  errorMessage: (context, event) =>
                    event.data.data.checkVerificationCode.errorMessage
                }),
                cond: (context, event) =>
                  event &&
                  event.data &&
                  event.data.data &&
                  event.data.data.checkVerificationCode &&
                  event.data.data.checkVerificationCode.errorMessage
              },
              {
                target: "#confirmPracticeBeingJoined",
                internal: false,
                actions: assign({
                  confirmationScreen: (context, event) =>
                    event.data.data.checkVerificationCode.confirmationScreen
                }),
                cond: (context, event) =>
                  event &&
                  event.data &&
                  event.data.data &&
                  event.data.data.checkVerificationCode &&
                  event.data.data.checkVerificationCode.confirmationScreen
              },
              {
                target: "#enterPatientDemographics",
                cond: (context, event) =>
                  context.accountCreationIntent === "PATIENT"
              },
              {
                target: "#enterOrgName",
                cond: (context, event) =>
                  context.accountCreationIntent === "PROVIDER" &&
                  context.connectionType === "SECURE_MESSAGE"
              },
              {
                target: "#enterProviderDemographics",
                cond: (context, event) =>
                  context.accountCreationIntent === "PROVIDER" &&
                  context.connectionType === "COLLEAGUE"
              }
            ],
            onError: {
              target: "awaitVerificationCodeEntry",
              internal: true,
              actions: assign({
                error: (context, event) => {
                  console.error(event);
                }
              })
            }
          }
        }
      }
    },
    confirmPracticeBeingJoined: {
      id: "confirmPracticeBeingJoined",
      on: {
        CONFIRM: [
          {
            target: "enterPhoneNumber",
            cond: ctx => ctx.connectionType === "COLLEAGUE"
          },
          {
            target: "enterProviderDemographics",
            cond: ctx => ctx.accountCreationIntent === "PROVIDER"
          },
          {
            target: "enterPatientDemographics",
            cond: ctx => ctx.accountCreationIntent === "PATIENT"
          }
        ]
      }
    },
    enterOrgName: {
      id: "enterOrgName",
      on: {
        CHANGE: {
          actions: assign({
            organizationName: (ctx, e) => e.data
          })
        },
        SUBMIT: "enterProviderDemographics",
        BACK: "enterPhoneVerificationCode"
      }
    },
    enterPatientDemographics: {
      id: "enterPatientDemographics",
      on: {
        CHANGE_FIRST_NAME: {
          actions: assign({
            firstName: (ctx, e) => e.data
          })
        },
        CHANGE_LAST_NAME: {
          actions: assign({
            lastName: (ctx, e) => e.data
          })
        },
        CHANGE_DOB: {
          actions: assign({
            dob: (ctx, e) => e.data
          })
        },
        CHANGE_GENDER: {
          actions: assign({
            gender: (ctx, e) => e.data
          })
        },
        CHANGE_GENDER_DETAIL: {
          actions: assign({
            genderDetail: (ctx, e) => e.data
          })
        },
        SUBMIT: "enterEmailAndPassword",
        BACK: "enterPhoneVerificationCode"
      }
    },
    enterProviderDemographics: {
      id: "enterProviderDemographics",
      on: {
        CHANGE_FIRST_NAME: {
          actions: assign({
            firstName: (ctx, e) => e.data
          })
        },
        CHANGE_LAST_NAME: {
          actions: assign({
            lastName: (ctx, e) => e.data
          })
        },
        CHANGE_SHORT_TITLE: {
          actions: assign({
            shortTitle: (ctx, e) => e.data
          })
        },
        SUBMIT: "enterEmailAndPassword",
        BACK: "enterPhoneVerificationCode"
      }
    },
    enterEmailAndPassword: {
      on: {
        CHANGE_EMAIL: {
          actions: assign({
            email: (ctx, e) => e.data
          })
        },
        CHANGE_PASSWORD: {
          actions: assign({
            password: (ctx, e) => e.data
          })
        },
        SUBMIT: [
          {
            target: "providerAccountCreated",
            cond: ctx =>
              ctx.connectionType === "COLLEAGUE" ||
              ctx.accountCreationIntent === "PROVIDER"
          },
          {
            target: "patientAccountCreated",
            cond: ctx => ctx.accountCreationIntent === "PATIENT"
          }
        ]
      }
    },
    patientAccountCreated: {
      type: "final"
    },
    providerAccountCreated: {
      type: "final"
    }
  },
  actions: {
    markAsProvider: assign({
      accountCreationIntent: "PROVIDER"
    }),
    markAsPatient: assign({
      accountCreationIntent: "PATIENT"
    })
  }
});