import { DataSource } from 'typeorm';
import { User } from '../../../repositories/users/entity/user.entity';
import { Account } from '../../../repositories/accounts/entity/account.entity';
import {
  License,
  LicenseOrder,
} from '../../../repositories/licenses/entity/license.entity';
import { SortCriteria } from '../../../repositories/sort_criteria/entity/sort_criteria.entity';

// TODO: [PBI 2379] 他のUtilityからコピペしてきたもの。後日整理される前提。
export const createAccountAndAdminUser = async (
  datasource: DataSource,
  adminExternalId: string,
): Promise<{
  accountId: number;
  adminId: number;
  role: string;
  tier: number;
}> => {
  const { identifiers: account_idf } = await datasource
    .getRepository(Account)
    .insert({
      tier: 1,
      country: 'JP',
      delegation_permission: false,
      locked: false,
      company_name: 'test inc.',
      verified: true,
      deleted_at: '',
      created_by: 'test_runner',
      created_at: new Date(),
      updated_by: 'updater',
      updated_at: new Date(),
    });
  const account = account_idf.pop() as Account;

  const { identifiers: user_idf } = await datasource
    .getRepository(User)
    .insert({
      account_id: account.id,
      external_id: adminExternalId,
      role: 'admin none',
      accepted_terms_version: '1.0',
      email_verified: true,
      auto_renew: true,
      license_alert: true,
      notification: true,
      encryption: true,
      encryption_password: 'password',
      prompt: true,
      created_by: 'test_runner',
      created_at: new Date(),
      updated_by: 'updater',
      updated_at: new Date(),
    });
  const user = user_idf.pop() as User;

  // Accountの管理者を設定する
  await datasource.getRepository(Account).update(
    { id: user.account_id },
    {
      primary_admin_user_id: user.id,
    },
  );

  const accountResult = await getAccount(datasource, account.id);
  const userResult = await getUser(datasource, user.id);

  return {
    accountId: account.id,
    adminId: user.id,
    role: userResult.role,
    tier: accountResult.tier,
  };
};

export const createAccount = async (
  datasource: DataSource,
  parentAccountId: number,
  tier: number,
  companyName: string,
): Promise<{ accountId: number }> => {
  const { identifiers } = await datasource.getRepository(Account).insert({
    parent_account_id: parentAccountId,
    tier: tier,
    country: 'JP',
    delegation_permission: false,
    locked: false,
    company_name: companyName,
    verified: true,
    deleted_at: '',
    created_by: 'test_runner',
    created_at: new Date(),
    updated_by: 'updater',
    updated_at: new Date(),
  });
  const account = identifiers.pop() as Account;
  return { accountId: account.id };
};

/**
 * テスト ユーティリティ: 指定IDのアカウントを取得する
 * @param dataSource データソース
 * @param id アカウントID
 * @returns 該当アカウント
 */
export const getAccount = async (dataSource: DataSource, id: number) => {
  return await dataSource.getRepository(Account).findOne({
    where: { id: id },
  });
};

/**
 * テスト ユーティリティ: すべてのアカウントを取得する
 * @param dataSource データソース
 * @returns　該当アカウント一覧
 */
export const getAccounts = async (
  dataSource: DataSource,
): Promise<Account[]> => {
  return await dataSource.getRepository(Account).find();
};

/**
 * テスト ユーティリティ: 指定ExternalIdのユーザーを取得する
 * @param dataSource データソース
 * @param externalId 外部ID
 * @returns 該当ユーザー
 */
export const getUserFromExternalID = async (
  dataSource: DataSource,
  externalId: string,
) => {
  return await dataSource.getRepository(User).findOne({
    where: { external_id: externalId },
  });
};

/**
 * テスト ユーティリティ: 指定Idのユーザーを取得する
 * @param dataSource データソース
 * @param externalId 外部ID
 * @returns 該当ユーザー
 */
export const getUser = async (
  datasource: DataSource,
  id: number,
): Promise<User> => {
  const user = await datasource.getRepository(User).findOne({
    where: {
      id: id,
    },
  });
  return user;
};

/**
 * テスト ユーティリティ: すべてのユーザーを取得する
 * @param dataSource データソース
 * @returns 該当ユーザー一覧
 */
export const getUsers = async (dataSource: DataSource): Promise<User[]> => {
  return await dataSource.getRepository(User).find();
};

/**
 * テスト ユーティリティ: すべてのソート条件を取得する
 * @param dataSource データソース
 * @returns 該当ソート条件一覧
 */
export const getSortCriteria = async (dataSource: DataSource) => {
  return await dataSource.getRepository(SortCriteria).find();
};

export const createLicense = async (
  datasource: DataSource,
  accountId: number,
): Promise<void> => {
  const { identifiers } = await datasource.getRepository(License).insert({
    expiry_date: null,
    account_id: accountId,
    type: 'NORMAL',
    status: 'Unallocated',
    allocated_user_id: null,
    order_id: null,
    deleted_at: null,
    delete_order_id: null,
    created_by: 'test_runner',
    created_at: new Date(),
    updated_by: 'updater',
    updated_at: new Date(),
  });
  identifiers.pop() as License;
};

// 有効期限・ステータス付きのライセンスを作成
export const createLicenseSetExpiryDateAndStatus = async (
  datasource: DataSource,
  accountId: number,
  expiryDate: Date,
  status: string,
): Promise<void> => {
  const { identifiers } = await datasource.getRepository(License).insert({
    expiry_date: expiryDate,
    account_id: accountId,
    type: 'NORMAL',
    status: status,
    allocated_user_id: null,
    order_id: null,
    deleted_at: null,
    delete_order_id: null,
    created_by: 'test_runner',
    created_at: new Date(),
    updated_by: 'updater',
    updated_at: new Date(),
  });
  identifiers.pop() as License;
};

export const createLicenseOrder = async (
  datasource: DataSource,
  fromAccountId: number,
  toAccountId: number,
  quantity: number,
  po_number = 'TEST123',
  ordered_at = new Date(),
): Promise<void> => {
  const { identifiers } = await datasource.getRepository(LicenseOrder).insert({
    po_number: po_number,
    from_account_id: fromAccountId,
    to_account_id: toAccountId,
    ordered_at: ordered_at,
    issued_at: null,
    quantity: quantity,
    status: 'Issue Requesting',
    canceled_at: null,
    created_by: 'test_runner',
    created_at: new Date(),
    updated_by: 'updater',
    updated_at: new Date(),
  });
  identifiers.pop() as License;
};

export const createUser = async (
  datasource: DataSource,
  accountId: number,
  external_id: string,
  role: string,
  author_id?: string | undefined,
): Promise<{ userId: number; externalId: string; authorId: string }> => {
  const { identifiers } = await datasource.getRepository(User).insert({
    account_id: accountId,
    external_id: external_id,
    role: role,
    accepted_terms_version: '1.0',
    author_id: author_id,
    email_verified: true,
    auto_renew: true,
    license_alert: true,
    notification: true,
    encryption: false,
    prompt: false,
    created_by: 'test_runner',
    created_at: new Date(),
    updated_by: 'updater',
    updated_at: new Date(),
  });
  const user = identifiers.pop() as User;
  return { userId: user.id, externalId: external_id, authorId: author_id };
};
