// tslint:disable:no-console
import { CognitoIdentityProvider } from '@aws-sdk/client-cognito-identity-provider';
import { fromEnv } from '@aws-sdk/credential-providers';

import { chevre } from '../../../lib/index';

export const USERPOOL_ID_OLD = String(process.env.USERPOOL_ID_OLD);
export const USERPOOL_ID_NEW = String(process.env.USERPOOL_ID_NEW);
const NEW_USERPOOL_PROVIDER_NAME = 'SSKTS';

// tslint:disable-next-line:max-func-body-length
export async function migrateUser(params: {
    id: string;
}): Promise<void> {
    const awsCredentials = fromEnv();
    const cognitoIdentityServiceProvider = new CognitoIdentityProvider({
        apiVersion: 'latest',
        region: 'ap-northeast-1',
        credentials: awsCredentials
    });

    // 旧会員を取得
    let oldPerson: chevre.factory.person.IPerson | undefined;

    try {
        const oldPersonRepo = await chevre.repository.Person.createInstance({
            userPoolId: USERPOOL_ID_OLD,
            cognitoIdentityServiceProvider
        });
        oldPerson = await oldPersonRepo.findById({ userId: params.id });
        console.log('oldPerson found', oldPerson.id, oldPerson.givenName, oldPerson.familyName);
    } catch (error) {
        let throwsError = true;
        if (error instanceof chevre.factory.errors.NotFound) {
            // 旧会員が存在しなければ何もしない
            throwsError = false;
        }

        if (throwsError) {
            throw error;
        }
    }

    if (oldPerson === undefined) {
        return;
    }

    // create user
    const newPersonRepo = await chevre.repository.Person.createInstance({
        userPoolId: USERPOOL_ID_NEW,
        cognitoIdentityServiceProvider
    });
    const newUsername = `${NEW_USERPOOL_PROVIDER_NAME}_${oldPerson.id}`;
    const newUserId = await new Promise<string>((resolve, reject) => {
        newPersonRepo.cognitoIdentityServiceProvider.adminCreateUser(
            {
                UserPoolId: USERPOOL_ID_NEW,
                Username: newUsername,
                UserAttributes: [
                    { Name: 'email_verified', Value: 'true' },
                    { Name: 'phone_number_verified', Value: 'false' },
                    { Name: 'phone_number', Value: oldPerson?.telephone },
                    { Name: 'given_name', Value: oldPerson?.givenName },
                    { Name: 'family_name', Value: oldPerson?.familyName },
                    { Name: 'email', Value: oldPerson?.email }
                ],
                // ValidationData?: AttributeListType;
                // TemporaryPassword?: PasswordType;
                // ForceAliasCreation?: ForceAliasCreation;
                MessageAction: 'SUPPRESS',
                DesiredDeliveryMediums: []
                // ClientMetadata?: ClientMetadataType;
            },
            (err, data) => {
                if (err) {
                    console.error('user not created.', err);
                    reject(err);
                } else {
                    resolve(String(data?.User?.Attributes?.find((a) => a.Name === 'sub')?.Value));
                }
            }
        );
    });
    console.log('user created.', newUserId);

    // link provider
    await new Promise<void>((resolve, reject) => {
        newPersonRepo.cognitoIdentityServiceProvider.adminLinkProviderForUser(
            {
                UserPoolId: USERPOOL_ID_NEW,
                DestinationUser: {
                    ProviderName: 'Cognito',
                    // ProviderAttributeName: 'userId',
                    ProviderAttributeValue: newUsername
                },
                SourceUser: {
                    ProviderName: NEW_USERPOOL_PROVIDER_NAME,
                    ProviderAttributeName: 'userId',
                    ProviderAttributeValue: params.id
                }
            },
            (err, data) => {
                if (err) {
                    console.error('user not linked.', err);
                    reject(err);
                } else {
                    console.log('user linked.', data);
                    resolve();
                }
            });
    });

    // disable link provider
    await new Promise<void>((resolve, reject) => {
        newPersonRepo.cognitoIdentityServiceProvider.adminDisableProviderForUser(
            {
                UserPoolId: USERPOOL_ID_NEW,
                User: {
                    ProviderName: 'Cognito',
                    ProviderAttributeName: 'Cognito_Subject',
                    ProviderAttributeValue: newUsername
                }
            },
            (err, data) => {
                if (err) {
                    console.error('user not disabled password.', err);
                    reject(err);
                } else {
                    console.log('user linked.', data);
                    resolve();
                }
            });
    });

    // add to group
    await new Promise<void>((resolve, reject) => {
        newPersonRepo.cognitoIdentityServiceProvider.adminAddUserToGroup(
            {
                UserPoolId: USERPOOL_ID_NEW,
                Username: newUsername,
                GroupName: `${USERPOOL_ID_NEW}_${NEW_USERPOOL_PROVIDER_NAME}`
            },
            (err, data) => {
                if (err) {
                    console.error('user not added to group.', err);
                    reject(err);
                } else {
                    console.log('user added to group.', data);
                    resolve();
                }
            });
    });
}
