// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import * as i18n from '../../core/i18n/i18n.js';
import type * as SDK from '../../core/sdk/sdk.js';
import * as Protocol from '../../generated/protocol.js';

import {Issue, IssueCategory, IssueKind} from './Issue.js';
import {
  type LazyMarkdownIssueDescription,
  type MarkdownIssueDescription,
  resolveLazyDescription,
} from './MarkdownIssueDescription.js';

const UIStrings = {
  /**
   * @description Title for Compression Dictionary Transport specification url link
   */
  compressionDictionaryTransport: 'Compression Dictionary Transport',
} as const;
const str_ = i18n.i18n.registerUIStrings('models/issues_manager/SharedDictionaryIssue.ts', UIStrings);
const i18nLazyString = i18n.i18n.getLazilyComputedLocalizedString.bind(undefined, str_);

export const enum IssueCode {
  USE_ERROR_CROSS_ORIGIN_NO_CORS_REQUEST = 'SharedDictionaryIssue::UseErrorCrossOriginNoCorsRequest',
  USE_ERROR_DICTIONARY_LOAD_FAILURE = 'SharedDictionaryIssue::UseErrorDictionaryLoadFailure',
  USE_ERROR_MATCHING_DICTIONARY_NOT_USED = 'SharedDictionaryIssue::UseErrorMatchingDictionaryNotUsed',
  USE_ERROR_UNEXPECTED_CONTENT_DICTIONARY_HEADER = 'SharedDictionaryIssue::UseErrorUnexpectedContentDictionaryHeader',
  WRITE_ERROR_CROSS_ORIGIN_NO_CORS_REQUEST = 'SharedDictionaryIssue::WriteErrorCossOriginNoCorsRequest',
  WRITE_ERROR_DISALLOWED_BY_SETTINGS = 'SharedDictionaryIssue::WriteErrorDisallowedBySettings',
  WRITE_ERROR_EXPIRED_RESPONSE = 'SharedDictionaryIssue::WriteErrorExpiredResponse',
  WRITE_ERROR_FEATURE_DISABLED = 'SharedDictionaryIssue::WriteErrorFeatureDisabled',
  WRITE_ERROR_INSUFFICIENT_RESOURCES = 'SharedDictionaryIssue::WriteErrorInsufficientResources',
  WRITE_ERROR_INVALID_MATCH_FIELD = 'SharedDictionaryIssue::WriteErrorInvalidMatchField',
  WRITE_ERROR_INVALID_STRUCTURED_HEADER = 'SharedDictionaryIssue::WriteErrorInvalidStructuredHeader',
  WRITE_ERROR_INVALID_TTL_FIELD = 'SharedDictionaryIssue::WriteErrorInvalidTTLField',
  WRITE_ERROR_NAVIGATION_REQUEST = 'SharedDictionaryIssue::WriteErrorNavigationRequest',
  WRITE_ERROR_NO_MATCH_FIELD = 'SharedDictionaryIssue::WriteErrorNoMatchField',
  WRITE_ERROR_NON_INTEGER_TTL_FIELD = 'SharedDictionaryIssue::WriteErrorNonIntegerTTLField',
  WRITE_ERROR_NON_LIST_MATCH_DEST_FIELD = 'SharedDictionaryIssue::WriteErrorNonListMatchDestField',
  WRITE_ERROR_NON_SECURE_CONTEXT = 'SharedDictionaryIssue::WriteErrorNonSecureContext',
  WRITE_ERROR_NON_STRING_ID_FIELD = 'SharedDictionaryIssue::WriteErrorNonStringIdField',
  WRITE_ERROR_NON_STRING_IN_MATCH_DEST_LIST = 'SharedDictionaryIssue::WriteErrorNonStringInMatchDestList',
  WRITE_ERROR_NON_STRING_MATCH_FIELD = 'SharedDictionaryIssue::WriteErrorNonStringMatchField',
  WRITE_ERROR_NON_TOKEN_TYPE_FIELD = 'SharedDictionaryIssue::WriteErrorNonTokenTypeField',
  WRITE_ERROR_REQUEST_ABORTED = 'SharedDictionaryIssue::WriteErrorRequestAborted',
  WRITE_ERROR_SHUTTING_DOWN = 'SharedDictionaryIssue::WriteErrorShuttingDown',
  WRITE_ERROR_TOO_LONG_ID_FIELD = 'SharedDictionaryIssue::WriteErrorTooLongIdField',
  WRITE_ERROR_UNSUPPORTED_TYPE = 'SharedDictionaryIssue::WriteErrorUnsupportedType',
  UNKNOWN = 'SharedDictionaryIssue::WriteErrorUnknown',
}

function getIssueCode(details: Protocol.Audits.SharedDictionaryIssueDetails): IssueCode {
  switch (details.sharedDictionaryError) {
    case Protocol.Audits.SharedDictionaryError.UseErrorCrossOriginNoCorsRequest:
      return IssueCode.USE_ERROR_CROSS_ORIGIN_NO_CORS_REQUEST;
    case Protocol.Audits.SharedDictionaryError.UseErrorDictionaryLoadFailure:
      return IssueCode.USE_ERROR_DICTIONARY_LOAD_FAILURE;
    case Protocol.Audits.SharedDictionaryError.UseErrorMatchingDictionaryNotUsed:
      return IssueCode.USE_ERROR_MATCHING_DICTIONARY_NOT_USED;
    case Protocol.Audits.SharedDictionaryError.UseErrorUnexpectedContentDictionaryHeader:
      return IssueCode.USE_ERROR_UNEXPECTED_CONTENT_DICTIONARY_HEADER;
    case Protocol.Audits.SharedDictionaryError.WriteErrorCossOriginNoCorsRequest:
      return IssueCode.WRITE_ERROR_CROSS_ORIGIN_NO_CORS_REQUEST;
    case Protocol.Audits.SharedDictionaryError.WriteErrorDisallowedBySettings:
      return IssueCode.WRITE_ERROR_DISALLOWED_BY_SETTINGS;
    case Protocol.Audits.SharedDictionaryError.WriteErrorExpiredResponse:
      return IssueCode.WRITE_ERROR_EXPIRED_RESPONSE;
    case Protocol.Audits.SharedDictionaryError.WriteErrorFeatureDisabled:
      return IssueCode.WRITE_ERROR_FEATURE_DISABLED;
    case Protocol.Audits.SharedDictionaryError.WriteErrorInsufficientResources:
      return IssueCode.WRITE_ERROR_INSUFFICIENT_RESOURCES;
    case Protocol.Audits.SharedDictionaryError.WriteErrorInvalidMatchField:
      return IssueCode.WRITE_ERROR_INVALID_MATCH_FIELD;
    case Protocol.Audits.SharedDictionaryError.WriteErrorInvalidStructuredHeader:
      return IssueCode.WRITE_ERROR_INVALID_STRUCTURED_HEADER;
    case Protocol.Audits.SharedDictionaryError.WriteErrorInvalidTTLField:
      return IssueCode.WRITE_ERROR_INVALID_TTL_FIELD;
    case Protocol.Audits.SharedDictionaryError.WriteErrorNavigationRequest:
      return IssueCode.WRITE_ERROR_NAVIGATION_REQUEST;
    case Protocol.Audits.SharedDictionaryError.WriteErrorNoMatchField:
      return IssueCode.WRITE_ERROR_NO_MATCH_FIELD;
    case Protocol.Audits.SharedDictionaryError.WriteErrorNonIntegerTTLField:
      return IssueCode.WRITE_ERROR_NON_INTEGER_TTL_FIELD;
    case Protocol.Audits.SharedDictionaryError.WriteErrorNonListMatchDestField:
      return IssueCode.WRITE_ERROR_NON_LIST_MATCH_DEST_FIELD;
    case Protocol.Audits.SharedDictionaryError.WriteErrorNonSecureContext:
      return IssueCode.WRITE_ERROR_NON_SECURE_CONTEXT;
    case Protocol.Audits.SharedDictionaryError.WriteErrorNonStringIdField:
      return IssueCode.WRITE_ERROR_NON_STRING_ID_FIELD;
    case Protocol.Audits.SharedDictionaryError.WriteErrorNonStringInMatchDestList:
      return IssueCode.WRITE_ERROR_NON_STRING_IN_MATCH_DEST_LIST;
    case Protocol.Audits.SharedDictionaryError.WriteErrorNonStringMatchField:
      return IssueCode.WRITE_ERROR_NON_STRING_MATCH_FIELD;
    case Protocol.Audits.SharedDictionaryError.WriteErrorNonTokenTypeField:
      return IssueCode.WRITE_ERROR_NON_TOKEN_TYPE_FIELD;
    case Protocol.Audits.SharedDictionaryError.WriteErrorRequestAborted:
      return IssueCode.WRITE_ERROR_REQUEST_ABORTED;
    case Protocol.Audits.SharedDictionaryError.WriteErrorShuttingDown:
      return IssueCode.WRITE_ERROR_SHUTTING_DOWN;
    case Protocol.Audits.SharedDictionaryError.WriteErrorTooLongIdField:
      return IssueCode.WRITE_ERROR_TOO_LONG_ID_FIELD;
    case Protocol.Audits.SharedDictionaryError.WriteErrorUnsupportedType:
      return IssueCode.WRITE_ERROR_UNSUPPORTED_TYPE;
    default:
      return IssueCode.UNKNOWN;
  }
}

export class SharedDictionaryIssue extends Issue<Protocol.Audits.SharedDictionaryIssueDetails, IssueCode> {
  constructor(
      issueDetails: Protocol.Audits.SharedDictionaryIssueDetails, issuesModel: SDK.IssuesModel.IssuesModel|null) {
    super(
        {
          code: getIssueCode(issueDetails),
          umaCode: [
            Protocol.Audits.InspectorIssueCode.SharedDictionaryIssue,
            issueDetails.sharedDictionaryError,
          ].join('::'),
        },
        issueDetails, issuesModel);
  }

  override requests(): Iterable<Protocol.Audits.AffectedRequest> {
    if (this.details().request) {
      return [this.details().request];
    }
    return [];
  }

  getCategory(): IssueCategory {
    return IssueCategory.OTHER;
  }

  getDescription(): MarkdownIssueDescription|null {
    const description = issueDescriptions.get(this.details().sharedDictionaryError);
    if (!description) {
      return null;
    }
    return resolveLazyDescription(description);
  }

  primaryKey(): string {
    return JSON.stringify(this.details());
  }

  getKind(): IssueKind {
    return IssueKind.PAGE_ERROR;
  }

  static fromInspectorIssue(
      issuesModel: SDK.IssuesModel.IssuesModel|null,
      inspectorIssue: Protocol.Audits.InspectorIssue): SharedDictionaryIssue[] {
    const details = inspectorIssue.details.sharedDictionaryIssueDetails;
    if (!details) {
      console.warn('Shared Dictionary issue without details received.');
      return [];
    }
    return [new SharedDictionaryIssue(details, issuesModel)];
  }
}
const specLinks = [{
  link: 'https://datatracker.ietf.org/doc/draft-ietf-httpbis-compression-dictionary/',
  linkTitle: i18nLazyString(UIStrings.compressionDictionaryTransport),
}];

const issueDescriptions = new Map<Protocol.Audits.SharedDictionaryError, LazyMarkdownIssueDescription>([

  [
    Protocol.Audits.SharedDictionaryError.UseErrorCrossOriginNoCorsRequest,
    {
      file: 'sharedDictionaryUseErrorCrossOriginNoCorsRequest.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.UseErrorDictionaryLoadFailure,
    {
      file: 'sharedDictionaryUseErrorDictionaryLoadFailure.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.UseErrorMatchingDictionaryNotUsed,
    {
      file: 'sharedDictionaryUseErrorMatchingDictionaryNotUsed.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.UseErrorUnexpectedContentDictionaryHeader,
    {
      file: 'sharedDictionaryUseErrorUnexpectedContentDictionaryHeader.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorCossOriginNoCorsRequest,
    {
      file: 'sharedDictionaryWriteErrorCossOriginNoCorsRequest.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorDisallowedBySettings,
    {
      file: 'sharedDictionaryWriteErrorDisallowedBySettings.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorExpiredResponse,
    {
      file: 'sharedDictionaryWriteErrorExpiredResponse.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorFeatureDisabled,
    {
      file: 'sharedDictionaryWriteErrorFeatureDisabled.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorInsufficientResources,
    {
      file: 'sharedDictionaryWriteErrorInsufficientResources.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorInvalidMatchField,
    {
      file: 'sharedDictionaryWriteErrorInvalidMatchField.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorInvalidStructuredHeader,
    {
      file: 'sharedDictionaryWriteErrorInvalidStructuredHeader.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorInvalidTTLField,
    {
      file: 'sharedDictionaryWriteErrorInvalidTTLField.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorNavigationRequest,
    {
      file: 'sharedDictionaryWriteErrorNavigationRequest.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorNoMatchField,
    {
      file: 'sharedDictionaryWriteErrorNoMatchField.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorNonIntegerTTLField,
    {
      file: 'sharedDictionaryWriteErrorNonIntegerTTLField.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorNonListMatchDestField,
    {
      file: 'sharedDictionaryWriteErrorNonListMatchDestField.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorNonSecureContext,
    {
      file: 'sharedDictionaryWriteErrorNonSecureContext.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorNonStringIdField,
    {
      file: 'sharedDictionaryWriteErrorNonStringIdField.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorNonStringInMatchDestList,
    {
      file: 'sharedDictionaryWriteErrorNonStringInMatchDestList.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorNonStringMatchField,
    {
      file: 'sharedDictionaryWriteErrorNonStringMatchField.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorNonTokenTypeField,
    {
      file: 'sharedDictionaryWriteErrorNonTokenTypeField.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorRequestAborted,
    {
      file: 'sharedDictionaryWriteErrorRequestAborted.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorShuttingDown,
    {
      file: 'sharedDictionaryWriteErrorShuttingDown.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorTooLongIdField,
    {
      file: 'sharedDictionaryWriteErrorTooLongIdField.md',
      links: specLinks,
    },
  ],
  [
    Protocol.Audits.SharedDictionaryError.WriteErrorUnsupportedType,
    {
      file: 'sharedDictionaryWriteErrorUnsupportedType.md',
      links: specLinks,
    },
  ],
]);
