// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { importProvidersFrom } from "@angular/core";
import { RouterModule } from "@angular/router";
import {
  applicationConfig,
  componentWrapperDecorator,
  Meta,
  moduleMetadata,
  StoryObj,
} from "@storybook/angular";
import { BehaviorSubject, of } from "rxjs";

import { OrganizationUserType } from "@bitwarden/common/admin-console/enums";
import { PermissionsApi } from "@bitwarden/common/admin-console/models/api/permissions.api";
import {
  CollectionAccessSelectionView,
  CollectionAdminView,
  Unassigned,
} from "@bitwarden/common/admin-console/models/collections";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
import { AvatarService } from "@bitwarden/common/auth/abstractions/avatar.service";
import { TokenService } from "@bitwarden/common/auth/abstractions/token.service";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { BillingAccountProfileStateService } from "@bitwarden/common/billing/abstractions";
import { EventCollectionService } from "@bitwarden/common/dirt/event-logs";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import {
  Environment,
  EnvironmentService,
} from "@bitwarden/common/platform/abstractions/environment.service";
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
import { PremiumUpgradePromptService } from "@bitwarden/common/vault/abstractions/premium-upgrade-prompt.service";
import { TotpService } from "@bitwarden/common/vault/abstractions/totp.service";
import { CipherType } from "@bitwarden/common/vault/enums";
import { AttachmentView } from "@bitwarden/common/vault/models/view/attachment.view";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { LoginUriView } from "@bitwarden/common/vault/models/view/login-uri.view";
import { LoginView } from "@bitwarden/common/vault/models/view/login.view";
import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service";
import { RestrictedItemTypesService } from "@bitwarden/common/vault/services/restricted-item-types.service";
import { CipherViewLike } from "@bitwarden/common/vault/utils/cipher-view-like-utils";
import { LayoutComponent, StorybookGlobalStateProvider, ToastService } from "@bitwarden/components";
import { GlobalStateProvider } from "@bitwarden/state";
import { RoutedVaultFilterService, PasswordRepromptService } from "@bitwarden/vault";

import { GroupView } from "../../../admin-console/organizations/core";
import { PreloadedEnglishI18nModule } from "../../../core/tests";

import { VaultItemsComponent } from "./vault-items.component";
import { VaultItemsModule } from "./vault-items.module";

const organizations = [...new Array(3).keys()].map(createOrganization);
const groups = [...Array(3).keys()].map(createGroupView);
const collections = [...Array(5).keys()].map(createCollectionView);
const ciphers = [...Array(50).keys()].map((i) => createCipherView(i));
const deletedCiphers = [...Array(15).keys()].map((i) => createCipherView(i, true));
const organizationOnlyCiphers = ciphers.filter((c) => c.organizationId != undefined);
const deletedOrganizationOnlyCiphers = deletedCiphers.filter((c) => c.organizationId != undefined);

export default {
  title: "Web/Vault/Items",
  component: VaultItemsComponent,
  decorators: [
    componentWrapperDecorator((story) => `<bit-layout>${story}</bit-layout>`),
    moduleMetadata({
      imports: [VaultItemsModule, RouterModule, LayoutComponent],
      providers: [
        {
          provide: EnvironmentService,
          useValue: {
            getIconsUrl() {
              return "";
            },
            environment$: new BehaviorSubject({
              getIconsUrl() {
                return "";
              },
            } as Environment).asObservable(),
          } as Partial<EnvironmentService>,
        },
        {
          provide: StateService,
          useValue: {
            accounts$: new BehaviorSubject({ "1": { profile: { name: "Foo" } } }).asObservable(),
            async getShowFavicon() {
              return true;
            },
          } as Partial<StateService>,
        },
        {
          provide: DomainSettingsService,
          useValue: {
            showFavicons$: new BehaviorSubject(true).asObservable(),
            getShowFavicon() {
              return true;
            },
          } as Partial<DomainSettingsService>,
        },
        {
          provide: AvatarService,
          useValue: {
            avatarColor$: of("#FF0000"),
          } as Partial<AvatarService>,
        },
        {
          provide: TokenService,
          useValue: {
            async getUserId() {
              return "user-id";
            },
            async getName() {
              return "name";
            },
            async getEmail() {
              return "email";
            },
          } as Partial<TokenService>,
        },
        {
          provide: ConfigService,
          useValue: {
            getFeatureFlag$() {
              // does not currently affect any display logic, default all to OFF
              return of(false);
            },
          },
        },
        {
          provide: CipherAuthorizationService,
          useValue: {
            canDeleteCipher$() {
              return of(true);
            },
            canRestoreCipher$() {
              return of(true);
            },
            canCloneCipher$() {
              return of(true);
            },
          },
        },
        {
          provide: RestrictedItemTypesService,
          useValue: {
            restricted$: of([]), // No restricted item types for this story
            isCipherRestricted: () => false, // No restrictions for this story
          },
        },
        {
          provide: RoutedVaultFilterService,
          useValue: {
            filter$: of({
              organizationId: null,
              collectionId: null,
              folderId: null,
              type: null,
            }),
          },
        },
        {
          provide: AccountService,
          useValue: {
            async getAccount() {
              return { id: "account-id", profile: { name: "Foo" } };
            },
          } as Partial<AccountService>,
        },
        {
          provide: PlatformUtilsService,
          useValue: {
            isDesktop() {
              return false;
            },
          } as Partial<PlatformUtilsService>,
        },
        {
          provide: PremiumUpgradePromptService,
          useValue: () => {},
        },
        {
          provide: BillingAccountProfileStateService,
          useValue: {
            hasPremiumFromAnySource$: () => new BehaviorSubject(false),
          },
        },
        {
          provide: AccountService,
          useValue: {
            activeAccount$: of({
              name: "User 1",
            }),
          } as Partial<AccountService>,
        },
        {
          provide: CipherService,
          useValue: () => {},
        },
      ],
    }),
    applicationConfig({
      providers: [
        importProvidersFrom(RouterModule.forRoot([], { useHash: true })),
        importProvidersFrom(PreloadedEnglishI18nModule),
        {
          provide: GlobalStateProvider,
          useClass: StorybookGlobalStateProvider,
        },
        {
          provide: PlatformUtilsService,
          useValue: () => {},
        },
        {
          provide: ToastService,
          useValue: () => {},
        },
        {
          provide: EventCollectionService,
          useValue: () => {},
        },
        {
          provide: PasswordRepromptService,
          useValue: () => {},
        },
        {
          provide: TotpService,
          useValue: () => {},
        },
        {
          provide: BillingAccountProfileStateService,
          useValue: () => {},
        },
        {
          provide: AccountService,
          useValue: {
            activeAccount$: of({
              name: "User 1",
            }),
          } as Partial<AccountService>,
        },
      ],
    }),
  ],
  args: {
    disabled: false,
    allCollections: collections,
    allGroups: groups,
    allOrganizations: organizations,
  },
  argTypes: { onEvent: { action: "onEvent" } },
} as Meta;

type Story = StoryObj<VaultItemsComponent<CipherViewLike>>;

export const Individual: Story = {
  args: {
    ciphers,
    collections: [],
    showOwner: true,
    showCollections: false,
    showGroups: false,
    showPremiumFeatures: true,
    showBulkMove: true,
    showBulkTrashOptions: false,
    useEvents: false,
  },
};

export const IndividualDisabled: Story = {
  args: {
    ciphers,
    collections: [],
    disabled: true,
    showOwner: true,
    showCollections: false,
    showGroups: false,
    showPremiumFeatures: true,
    showBulkMove: true,
    showBulkTrashOptions: false,
    useEvents: false,
  },
};

export const IndividualTrash: Story = {
  args: {
    ciphers: deletedCiphers,
    collections: [],
    showOwner: true,
    showCollections: false,
    showGroups: false,
    showPremiumFeatures: true,
    showBulkMove: false,
    showBulkTrashOptions: true,
    useEvents: false,
  },
};

export const IndividualTopLevelCollection: Story = {
  args: {
    ciphers: [],
    collections,
    showOwner: true,
    showCollections: false,
    showGroups: false,
    showPremiumFeatures: true,
    showBulkMove: false,
    showBulkTrashOptions: false,
    useEvents: false,
  },
};

export const IndividualSecondLevelCollection: Story = {
  args: {
    ciphers,
    collections,
    showOwner: true,
    showCollections: false,
    showGroups: false,
    showPremiumFeatures: true,
    showBulkMove: true,
    showBulkTrashOptions: false,
    useEvents: false,
  },
};

export const OrganizationVault: Story = {
  args: {
    ciphers: organizationOnlyCiphers,
    collections: [],
    showOwner: false,
    showCollections: true,
    showGroups: false,
    showPremiumFeatures: true,
    showBulkMove: false,
    showBulkTrashOptions: false,
    useEvents: true,
  },
};

export const OrganizationTrash: Story = {
  args: {
    ciphers: deletedOrganizationOnlyCiphers,
    collections: [],
    showOwner: false,
    showCollections: true,
    showGroups: false,
    showPremiumFeatures: true,
    showBulkMove: false,
    showBulkTrashOptions: true,
    useEvents: true,
  },
};

const unassignedCollection = new CollectionAdminView({
  id: Unassigned as CollectionId,
  name: "Unassigned",
  organizationId: "org id" as OrganizationId,
});
export const OrganizationTopLevelCollection: Story = {
  args: {
    ciphers: [],
    collections: collections.concat(unassignedCollection),
    showOwner: false,
    showCollections: false,
    showGroups: true,
    showPremiumFeatures: true,
    showBulkMove: false,
    showBulkTrashOptions: false,
    useEvents: true,
  },
};

export const OrganizationSecondLevelCollection: Story = {
  args: {
    ciphers: organizationOnlyCiphers,
    collections,
    showOwner: false,
    showCollections: false,
    showGroups: true,
    showPremiumFeatures: true,
    showBulkMove: false,
    showBulkTrashOptions: false,
    useEvents: true,
  },
};

function createCipherView(i: number, deleted = false): CipherView {
  const organization = organizations[i % (organizations.length + 1)];
  const collection = collections[i % (collections.length + 1)];
  const view = new CipherView();
  view.id = `cipher-${i}`;
  view.name = `Vault item ${i}`;
  view.type = CipherType.Login;
  view.organizationId = organization?.id;
  view.deletedDate = deleted ? new Date() : undefined;
  view.login = new LoginView();
  view.login.username = i % 10 === 0 ? undefined : `username-${i}`;
  view.login.totp = i % 2 === 0 ? "I65VU7K5ZQL7WB4E" : undefined;
  view.login.uris = [new LoginUriView()];
  view.login.uris[0].uri = "https://bitwarden.com";
  view.collectionIds = collection ? [collection.id] : [];

  if (i === 0) {
    // Old attachment
    const attachment = new AttachmentView();
    view.organizationId = null;
    view.collectionIds = [];
    view.attachments = [attachment];
  } else if (i % 5 === 0) {
    const attachment = new AttachmentView();
    attachment.key = new SymmetricCryptoKey(new Uint8Array(32));
    view.attachments = [attachment];
  }

  return view;
}

function createCollectionView(i: number): CollectionAdminView {
  const organization = organizations[i % (organizations.length + 1)];
  const group = groups[i % (groups.length + 1)];
  const view = new CollectionAdminView({
    id: `collection-${i}` as CollectionId,
    name: `Collection ${i}`,
    organizationId: organization?.id ?? ("orgId" as OrganizationId),
  });

  if (group !== undefined) {
    view.groups = [
      new CollectionAccessSelectionView({
        id: group.id,
        hidePasswords: false,
        readOnly: false,
        manage: false,
      }),
    ];
  }

  view.manage = true;
  return view;
}

function createGroupView(i: number): GroupView {
  const organization = organizations[i % organizations.length];
  return new GroupView({
    id: `group-${i}`,
    name: `Group ${i}`,
    organizationId: organization.id,
  });
}

function createOrganization(i: number): Organization {
  const organization = new Organization();
  organization.id = `organization-${i}` as OrganizationId;
  organization.name = `Organization ${i}`;
  organization.type = OrganizationUserType.Owner;
  organization.permissions = new PermissionsApi();
  return organization;
}
