import { ApiProperty } from '@nestjs/swagger';
import {
  IsEmail,
  IsInt,
  IsOptional,
  Matches,
  MaxLength,
  Min,
  ArrayMinSize,
  MinLength,
  IsArray,
  IsIn,
  ArrayMaxSize,
  ValidateNested,
} from 'class-validator';
import { IsAdminPasswordvalid } from '../../../common/validators/admin.validator';
import { IsUnique } from '../../../common/validators/IsUnique.validator';
import { Type } from 'class-transformer';
import {
  IsInitialValue,
  IsRecorderAllowed,
} from '../../../common/validators/worktype.validator';
import { OPTION_ITEM_VALUE_TYPE } from '../../../constants';

export class CreateAccountRequest {
  @ApiProperty()
  @MaxLength(255)
  companyName: string;

  @ApiProperty({
    description: '国名(ISO 3166-1 alpha-2)',
    minLength: 2,
    maxLength: 2,
  })
  @MinLength(2)
  @MaxLength(2)
  country: string;

  @ApiProperty({ required: false })
  @Type(() => Number)
  @IsInt()
  @IsOptional()
  dealerAccountId?: number;

  @ApiProperty()
  @MaxLength(256) // AzureAdB2Cの仕様上、256文字まで[https://learn.microsoft.com/ja-jp/azure/active-directory-b2c/user-profile-attributes]
  adminName: string;

  @ApiProperty()
  @IsEmail({ blacklisted_chars: '*' })
  adminMail: string;

  @ApiProperty()
  @IsAdminPasswordvalid()
  adminPassword: string;

  @ApiProperty({ description: '同意済み利用規約のバージョン(EULA)' })
  @MaxLength(255)
  acceptedEulaVersion: string;

  @ApiProperty({ description: '同意済みプライバシーポリシーのバージョン' })
  @MaxLength(255)
  acceptedPrivacyNoticeVersion: string;

  @ApiProperty({ description: '同意済み利用規約のバージョン(DPA)' })
  @MaxLength(255)
  acceptedDpaVersion: string;

  @ApiProperty({ description: 'reCAPTCHA Token' })
  token: string;
}

export class GetLicenseSummaryRequest {
  @ApiProperty()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  accountId: number;
}

export class GetTypistGroupRequest {
  @ApiProperty()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  typistGroupId: number;
}

export class CreateTypistGroupRequest {
  @ApiProperty({ minLength: 1, maxLength: 50 })
  @MinLength(1)
  @MaxLength(50)
  typistGroupName: string;
  @ApiProperty({ minItems: 1, isArray: true, type: 'integer' })
  @ArrayMinSize(1)
  @IsArray()
  @IsInt({ each: true })
  @Min(1, { each: true })
  @IsUnique()
  typistIds: number[];
}

export class UpdateTypistGroupRequest {
  @ApiProperty({ minLength: 1, maxLength: 50 })
  @MinLength(1)
  @MaxLength(50)
  typistGroupName: string;
  @ApiProperty({ minItems: 1, isArray: true, type: 'integer' })
  @ArrayMinSize(1)
  @IsArray()
  @IsInt({ each: true })
  @Min(1, { each: true })
  @IsUnique()
  typistIds: number[];
}
export class UpdateTypistGroupRequestParam {
  @ApiProperty()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  typistGroupId: number;
}
export class CreatePartnerAccountRequest {
  @ApiProperty()
  @MaxLength(255)
  companyName: string;
  @ApiProperty({
    description: '国名(ISO 3166-1 alpha-2)',
    minLength: 2,
    maxLength: 2,
  })
  @MinLength(2)
  @MaxLength(2)
  country: string;
  @ApiProperty()
  @MaxLength(256) // AzureAdB2Cの仕様上、256文字まで[https://learn.microsoft.com/ja-jp/azure/active-directory-b2c/user-profile-attributes]
  adminName: string;
  @ApiProperty()
  @IsEmail({ blacklisted_chars: '*' })
  email: string;
}

export class GetPartnerLicensesRequest {
  @ApiProperty()
  @IsInt()
  @Type(() => Number)
  @Min(0)
  limit: number;
  @ApiProperty()
  @IsInt()
  @Type(() => Number)
  @Min(0)
  offset: number;
  @ApiProperty()
  @IsInt()
  @Type(() => Number)
  accountId: number;
}

export class GetOrderHistoriesRequest {
  @ApiProperty({ description: '取得件数' })
  @IsInt()
  @Min(0)
  @Type(() => Number)
  limit: number;
  @ApiProperty({ description: '開始位置' })
  @IsInt()
  @Min(0)
  @Type(() => Number)
  offset: number;
  @ApiProperty({ description: 'アカウントID' })
  @IsInt()
  @Type(() => Number)
  accountId: number;
}

export class IssueLicenseRequest {
  @ApiProperty({ description: '注文元アカウントID' })
  @IsInt()
  @Type(() => Number)
  orderedAccountId: number;
  @ApiProperty({ description: 'POナンバー' })
  @Matches(/^[A-Z0-9]+$/)
  poNumber: string;
}

export class CancelIssueRequest {
  @ApiProperty({ description: '注文元アカウントID' })
  @IsInt()
  @Type(() => Number)
  orderedAccountId: number;

  @ApiProperty({ description: 'POナンバー' })
  @Matches(/^[A-Z0-9]+$/)
  poNumber: string;
}

export class CreateWorktypesRequest {
  @ApiProperty({ minLength: 1, maxLength: 255, description: 'WorktypeID' })
  @MinLength(1)
  @MaxLength(16)
  @IsRecorderAllowed()
  worktypeId: string;
  @ApiProperty({ description: 'Worktypeの説明', required: false })
  @MaxLength(255)
  @IsOptional()
  description?: string;
}

export class UpdateWorktypesRequest {
  @ApiProperty({ minLength: 1, description: 'WorktypeID' })
  @MinLength(1)
  @MaxLength(16)
  @IsRecorderAllowed()
  worktypeId: string;
  @ApiProperty({ description: 'Worktypeの説明', required: false })
  @MaxLength(255)
  @IsOptional()
  description?: string;
}

export class PostWorktypeOptionItem {
  @ApiProperty({ maxLength: 16 })
  @MaxLength(16)
  @IsRecorderAllowed()
  itemLabel: string;
  @ApiProperty({
    maxLength: 20,
    description: `${Object.values(OPTION_ITEM_VALUE_TYPE).join(' / ')}`,
  })
  @MaxLength(20)
  @IsIn(Object.values(OPTION_ITEM_VALUE_TYPE))
  defaultValueType: string;
  @ApiProperty({ maxLength: 20 })
  @MaxLength(20)
  @IsRecorderAllowed()
  @IsInitialValue()
  initialValue: string;
}

export class GetOptionItemsRequestParam {
  @ApiProperty({ description: 'Worktypeの内部ID' })
  @Type(() => Number)
  @IsInt()
  @Min(1)
  id: number;
}

export class UpdateOptionItemsRequest {
  @ApiProperty({
    maxItems: 10,
    minItems: 10,
    type: [PostWorktypeOptionItem],
  })
  @IsArray()
  @ValidateNested({ each: true })
  @Type(() => PostWorktypeOptionItem)
  @ArrayMinSize(10)
  @ArrayMaxSize(10)
  optionItems: PostWorktypeOptionItem[];
}

export class UpdateOptionItemsRequestParam {
  @ApiProperty({ description: 'Worktypeの内部ID' })
  @Type(() => Number)
  @IsInt()
  @Min(1)
  id: number;
}

export class UpdateWorktypeRequestParam {
  @ApiProperty({ description: 'Worktypeの内部ID' })
  @Type(() => Number)
  @IsInt()
  @Min(1)
  id: number;
}

export class DeleteWorktypeRequestParam {
  @ApiProperty({ description: 'Worktypeの内部ID' })
  @Type(() => Number)
  @IsInt()
  @Min(1)
  id: number;
}

export class PostActiveWorktypeRequest {
  @ApiProperty({
    required: false,
    description: 'Active WorkTypeIDにするWorktypeの内部ID',
  })
  @IsOptional()
  @Type(() => Number)
  @IsInt()
  @Min(1)
  id?: number;
}

export class GetPartnersRequest {
  @ApiProperty({ description: '取得件数' })
  @IsInt()
  @Min(0)
  @Type(() => Number)
  limit: number;
  @ApiProperty({ description: '開始位置' })
  @IsInt()
  @Min(0)
  @Type(() => Number)
  offset: number;
}

export class UpdateAccountInfoRequest {
  @ApiProperty({ description: '親アカウントのID', required: false })
  @Type(() => Number)
  @IsInt()
  @IsOptional()
  parentAccountId?: number;
  @ApiProperty({ description: '代行操作許可' })
  @Type(() => Boolean)
  delegationPermission: boolean;
  @ApiProperty({ description: 'プライマリ管理者ID' })
  @Type(() => Number)
  @IsInt()
  primaryAdminUserId: number;
  @ApiProperty({ description: 'セカンダリ管理者ID', required: false })
  @Type(() => Number)
  @IsInt()
  @IsOptional()
  secondryAdminUserId?: number;
}

export class DeleteAccountRequest {
  @ApiProperty({ description: 'アカウントID' })
  @Type(() => Number)
  @IsInt()
  accountId: number;
}

export class GetAccountInfoMinimalAccessRequest {
  @ApiProperty({ description: 'idトークン' })
  idToken: string;
}

export class GetCompanyNameRequest {
  @ApiProperty()
  @IsInt()
  @Type(() => Number)
  accountId: number;
}

// ==============================
// RESPONSE
// ==============================

export class CreateAccountResponse {}

export class GetLicenseSummaryResponse {
  @ApiProperty()
  totalLicense: number;

  @ApiProperty()
  allocatedLicense: number;

  @ApiProperty()
  reusableLicense: number;

  @ApiProperty()
  freeLicense: number;

  @ApiProperty()
  expiringWithin14daysLicense: number;

  @ApiProperty()
  issueRequesting: number;

  @ApiProperty()
  numberOfRequesting: number;

  @ApiProperty()
  shortage: number;

  @ApiProperty()
  storageSize: number;

  @ApiProperty()
  usedSize: number;

  @ApiProperty()
  isStorageAvailable: boolean;
}

export class GetCompanyNameResponse {
  @ApiProperty()
  companyName: string;
}

export class Account {
  @ApiProperty()
  accountId: number;

  @ApiProperty()
  companyName: string;

  @ApiProperty()
  tier: number;

  @ApiProperty()
  country: string;

  @ApiProperty({ required: false })
  parentAccountId?: number;

  @ApiProperty()
  delegationPermission: boolean;

  @ApiProperty({ required: false })
  primaryAdminUserId?: number;

  @ApiProperty({ required: false })
  secondryAdminUserId?: number;

  @ApiProperty({ required: false })
  parentAccountName?: string;
}

export class Author {
  @ApiProperty({ description: 'Authorユーザーの内部ID' })
  id: number;
  @ApiProperty({ description: 'AuthorID' })
  authorId: string;
}

export class Typist {
  @ApiProperty({
    description: 'TypistのユーザーID',
  })
  id: number;

  @ApiProperty({ description: 'Typistのユーザー名' })
  name: string;
}

export class TypistGroup {
  @ApiProperty({
    description: 'TypistGroupのID',
  })
  id: number;

  @ApiProperty({ description: 'TypistGroup名' })
  name: string;
}

export class GetMyAccountResponse {
  @ApiProperty({ type: Account })
  account: Account;
}

export class GetAuthorsResponse {
  @ApiProperty({ type: [Author] })
  authors: Author[];
}

export class GetTypistsResponse {
  @ApiProperty({ type: [Typist] })
  typists: Typist[];
}

export class GetTypistGroupsResponse {
  @ApiProperty({ type: [TypistGroup] })
  typistGroups: TypistGroup[];
}

export class GetTypistGroupResponse {
  @ApiProperty()
  typistGroupName: string;
  @ApiProperty({ isArray: true, type: 'integer' })
  typistIds: number[];
}

export class CreateTypistGroupResponse {}

export class UpdateTypistGroupResponse {}

export class CreatePartnerAccountResponse {}

export class PartnerLicenseInfo {
  @ApiProperty({ description: 'アカウントID' })
  accountId: number;

  @ApiProperty({ description: '階層' })
  tier: number;

  @ApiProperty({ description: 'アカウント名' })
  companyName: string;

  @ApiProperty({
    description: '保有している有効期限が未設定あるいは有効期限内のライセンス数',
  })
  stockLicense: number;

  @ApiProperty({
    description:
      '子アカウントからの、未発行状態あるいは発行キャンセルされた注文の総ライセンス数',
  })
  issuedRequested: number;

  @ApiProperty({ description: '不足数（{Stock license} - {Issue Requested}）' })
  shortage: number;

  @ApiProperty({
    description:
      '未発行状態あるいは発行キャンセルされた注文の総ライセンス数（=IssueRequestingのStatusの注文の総ライセンス数）',
  })
  issueRequesting: number;
}
export class GetPartnerLicensesResponse {
  @ApiProperty()
  total: number;
  @ApiProperty({ type: PartnerLicenseInfo })
  ownPartnerLicense: PartnerLicenseInfo;
  @ApiProperty({ type: [PartnerLicenseInfo] })
  childrenPartnerLicenses: PartnerLicenseInfo[];
}

export class LicenseOrder {
  @ApiProperty({ description: '注文日付' })
  orderDate: string;
  @ApiProperty({ description: '発行日付', required: false })
  issueDate?: string;
  @ApiProperty({ description: '注文数' })
  numberOfOrder: number;
  @ApiProperty({ description: 'POナンバー' })
  poNumber: string;
  @ApiProperty({ description: '注文状態' })
  status: string;
}

export class GetOrderHistoriesResponse {
  @ApiProperty({ description: '合計件数' })
  total: number;
  @ApiProperty({ type: [LicenseOrder] })
  orderHistories: LicenseOrder[];
}

export class IssueLicenseResponse {}

export class Dealer {
  @ApiProperty({ description: 'アカウントID' })
  id: number;
  @ApiProperty({ description: '会社名' })
  name: string;
  @ApiProperty({ description: '国名(ISO 3166-1 alpha-2)' })
  country: string;
}

export class GetDealersResponse {
  @ApiProperty({ type: [Dealer] })
  dealers: Dealer[];
}

export class CancelIssueResponse {}

export class Worktype {
  @ApiProperty({ description: 'WorktypeのID' })
  id: number;
  @ApiProperty({ description: 'WorktypeID' })
  worktypeId: string;
  @ApiProperty({ description: 'Worktypeの説明', required: false })
  description?: string;
}

export class GetWorktypesResponse {
  @ApiProperty({ type: [Worktype] })
  worktypes: Worktype[];

  @ApiProperty({
    required: false,
    description: 'Active WorktypeIDに設定されているWorkTypeの内部ID',
  })
  active?: number;
}

export class CreateWorktypeResponse {}

export class UpdateWorktypeResponse {}

export class GetWorktypeOptionItem extends PostWorktypeOptionItem {
  @ApiProperty()
  id: number;
}

export class GetOptionItemsResponse {
  @ApiProperty({
    maxItems: 10,
    minItems: 10,
    type: [GetWorktypeOptionItem],
  })
  optionItems: GetWorktypeOptionItem[];
}

export class UpdateOptionItemsResponse {}

export class DeleteWorktypeResponse {}

export class PostActiveWorktypeResponse {}

export class Partner {
  @ApiProperty({ description: '会社名' })
  name: string;
  @ApiProperty({ description: '階層' })
  tier: number;
  @ApiProperty({ description: 'アカウントID' })
  accountId: number;
  @ApiProperty({ description: '国' })
  country: string;
  @ApiProperty({ description: 'プライマリ管理者' })
  primaryAdmin: string;
  @ApiProperty({ description: 'プライマリ管理者メールアドレス' })
  email: string;
  @ApiProperty({ description: '代行操作許可' })
  dealerManagement: boolean;
}

export class GetPartnersResponse {
  @ApiProperty({ description: '合計件数' })
  total: number;
  @ApiProperty({ type: [Partner] })
  partners: Partner[];
}

export class UpdateAccountInfoResponse {}

export class DeleteAccountResponse {}

export class GetAccountInfoMinimalAccessResponse {
  @ApiProperty({ description: '階層' })
  tier: number;
}

// ==============================
// Request/Response外の型
// TODO: Request/Response/その他の型を別ファイルに分ける
// ==============================
export class LicenseSummaryInfo {
  totalLicense: number;
  allocatedLicense: number;
  reusableLicense: number;
  freeLicense: number;
  expiringSoonLicense: number;
  issueRequesting: number;
  numberOfRequesting: number;
  allocatableLicenseWithMargin: number;
}

// 第五階層のshortage算出用
export class PartnerLicenseInfoForShortage {
  expiringSoonLicense?: number;
  allocatableLicenseWithMargin?: number;
}

// RepositoryからPartnerLicenseInfoに関する情報を取得する際の型
export type PartnerLicenseInfoForRepository = Omit<
  PartnerLicenseInfo & PartnerLicenseInfoForShortage,
  'shortage'
>;

// RepositoryからPartnerLicenseInfoに関する情報を取得する際の型
export type PartnerInfoFromDb = {
  name: string;
  tier: number;
  accountId: number;
  country: string;
  primaryAccountExternalId: string;
  dealerManagement: boolean;
};
