import type {
  Item, ItemId, Manifest, ManifestEntry, VaultConfig, SetupState,
  DeviceSettings, GeneratorRequest, VaultSettings, AttachmentRef, Device,
  FieldHistoryView,
} from './types';

// --- Session timeout config ---

export type SessionTimeoutConfig =
  | { mode: 'inactivity'; minutes: number }
  | { mode: 'every_time' };

// --- Messages a popup (or setup page) may send ---

export type PopupMessage =
  | { type: 'is_unlocked' }
  | { type: 'unlock'; passphrase: string }
  | { type: 'lock' }
  | { type: 'list_items'; group?: string }
  | { type: 'get_item'; id: ItemId }
  | { type: 'add_item'; item: Item }
  | { type: 'update_item'; id: ItemId; item: Item }
  | { type: 'delete_item'; id: ItemId }                 // soft-delete
  | { type: 'get_totp'; id: ItemId }
  | { type: 'sync' }
  | { type: 'get_setup_state' }
  | { type: 'save_setup'; config: VaultConfig; imageBase64: string }
  | { type: 'rate_passphrase'; passphrase: string }
  | { type: 'generate_password'; request: GeneratorRequest }
  | { type: 'generate_passphrase'; request: GeneratorRequest }
  | { type: 'fill_credentials'; id: ItemId; capturedTabId: number; capturedUrl: string }
  | { type: 'ack_autofill_origin'; hostname: string }
  | { type: 'get_settings' }
  | { type: 'update_settings'; settings: Partial<DeviceSettings> }
  | { type: 'get_vault_settings' }
  | { type: 'update_vault_settings'; settings: VaultSettings }
  | { type: 'get_blacklist' }
  | { type: 'remove_blacklist'; hostname: string }
  | { type: 'get_active_tab_url' }
  | { type: 'list_groups' }
  | { type: 'upload_attachment'; itemId: string; filename: string; mimeType: string; bytes: ArrayBuffer }
  | { type: 'download_attachment'; itemId: string; attachmentId: string }
  | { type: 'list_devices' }
  | { type: 'list_revoked' }
  | { type: 'add_device'; name: string; public_key: string }
  | { type: 'register_this_device'; name: string }
  | { type: 'revoke_device'; name: string }
  | { type: 'list_trashed' }
  | { type: 'restore_item'; id: ItemId }
  | { type: 'purge_item'; id: ItemId }
  | { type: 'purge_all_trash' }
  | { type: 'get_field_history'; id: ItemId }
  | { type: 'get_session_config' }
  | { type: 'update_session_config'; config: SessionTimeoutConfig }
  | { type: 'export_backup'; passphrase: string; includeImage: boolean }
  | {
      type: 'restore_backup';
      bytes: ArrayBuffer;
      passphrase: string;
      newRemote: { hostType: 'gitea' | 'github'; hostUrl: string; repoPath: string; apiToken: string };
    }
  | { type: 'parse_lastpass_csv'; bytes: ArrayBuffer }
  | { type: 'import_lastpass_commit'; items: Item[] }
  | { type: 'preview_totp_from_secret'; secret_b32: string }
  | { type: 'generate_recovery_qr'; passphrase: string }
  | { type: 'unwrap_recovery_qr'; payload_b64: string; passphrase: string }
  | { type: 'create_vault'; config: VaultConfig; passphrase: string;
      carrierImageBytes: ArrayBuffer; deviceName: string }
  | { type: 'attach_vault'; config: VaultConfig; passphrase: string;
      referenceImageBytes: ArrayBuffer; deviceName: string }
  | { type: 'get_vault_status' };

// --- Messages a content script may send ---

// Note deliberate absence of a `url` field — the SW derives origin from sender.tab.url.

export type ContentMessage =
  | { type: 'get_autofill_candidates' }
  | { type: 'get_credentials'; id: ItemId }
  | { type: 'check_credential'; username: string; password: string }
  | { type: 'blacklist_site' }
  | { type: 'capture_save_login'; username: string; password: string };

// --- Union for chrome.runtime.sendMessage call sites ---

export type Request = PopupMessage | ContentMessage;

// --- Response ---

export type Response =
  | { ok: true; data?: unknown }
  | { ok: false; error: string };

// --- Typed response helpers ---

export interface IsUnlockedResponse extends Extract<Response, { ok: true }> {
  data: { unlocked: boolean };
}

export interface ListItemsResponse extends Extract<Response, { ok: true }> {
  data: { items: Array<[ItemId, ManifestEntry]> };
}

export interface GetItemResponse extends Extract<Response, { ok: true }> {
  data: { item: Item };
}

export interface TotpResponse extends Extract<Response, { ok: true }> {
  data: { code: string; expires_at: number };
}

export interface AutofillCandidatesResponse extends Extract<Response, { ok: true }> {
  data: { candidates: Array<[ItemId, ManifestEntry]> };
}

export interface CredentialsResponse extends Extract<Response, { ok: true }> {
  data:
    | { requires_ack: true; hostname: string }
    | { username: string; password: string };
}

export interface SetupStateResponse extends Extract<Response, { ok: true }> {
  data: SetupState;
}

export interface GeneratePasswordResponse extends Extract<Response, { ok: true }> {
  data: { password: string };
}

export interface RatePassphraseResponse extends Extract<Response, { ok: true }> {
  data: { score: number; guesses_log10: number };
}

export interface VaultSettingsResponse extends Extract<Response, { ok: true }> {
  data: { settings: VaultSettings };
}

export interface UploadAttachmentResponse extends Extract<Response, { ok: true }> {
  data: { attachment: AttachmentRef };
}

export interface DownloadAttachmentResponse extends Extract<Response, { ok: true }> {
  data: { bytes: ArrayBuffer; filename: string; mimeType: string };
}

export interface ListDevicesResponse extends Extract<Response, { ok: true }> {
  data: { devices: Device[] };
}

export interface ListRevokedResponse extends Extract<Response, { ok: true }> {
  data: { revoked: Array<{ name: string; public_key: string; revoked_at: number; revoked_by: string }> };
}

export interface ListTrashedResponse extends Extract<Response, { ok: true }> {
  data: { items: Array<[ItemId, ManifestEntry]> };
}

export interface PurgeAllTrashResponse extends Extract<Response, { ok: true }> {
  data: { itemCount: number; orphanCount: number };
}

export interface FieldHistoryResponse extends Extract<Response, { ok: true }> {
  data: { history: FieldHistoryView[] };
}

// --- Capability sets (consumed by the router) ---

export const POPUP_ONLY_TYPES: ReadonlySet<PopupMessage['type']> = new Set([
  'is_unlocked', 'unlock', 'lock', 'list_items', 'get_item', 'add_item',
  'update_item', 'delete_item', 'get_totp', 'sync', 'get_setup_state',
  'save_setup', 'rate_passphrase', 'generate_password', 'generate_passphrase',
  'fill_credentials',
  'ack_autofill_origin', 'get_settings', 'update_settings',
  'get_vault_settings', 'update_vault_settings', 'get_blacklist',
  'remove_blacklist', 'get_active_tab_url', 'list_groups', 'upload_attachment', 'download_attachment',
  'list_devices', 'list_revoked', 'add_device', 'register_this_device', 'revoke_device',
  'list_trashed', 'restore_item', 'purge_item', 'purge_all_trash',
  'get_field_history',
  'get_session_config', 'update_session_config',
  'export_backup', 'restore_backup',
  'parse_lastpass_csv', 'import_lastpass_commit',
  'preview_totp_from_secret',
  'generate_recovery_qr', 'unwrap_recovery_qr',
  'create_vault', 'attach_vault', 'get_vault_status',
] as PopupMessage['type'][]);

export interface ExportBackupResponse extends Extract<Response, { ok: true }> {
  data: { bytes: ArrayBuffer };
}

export interface RestoreBackupResponse extends Extract<Response, { ok: true }> {
  data: {
    summary: { itemCount: number; attachmentCount: number; hasImage: boolean };
  };
}

export interface ParseLastPassCsvResponse extends Extract<Response, { ok: true }> {
  data: {
    items: Item[];
    warnings: Array<{ row: number; title?: string; message: string }>;
  };
}

export interface ImportLastPassCommitResponse extends Extract<Response, { ok: true }> {
  data: {
    summary: { itemCount: number };
  };
}

export interface CreateVaultResponse extends Extract<Response, { ok: true }> {
  data: { referenceImageBytes: Uint8Array; deviceName: string;
          recoveryQrAvailable: true };
}

export interface AttachVaultResponse extends Extract<Response, { ok: true }> {
  data: { deviceName: string };
}

export interface GetVaultStatusResponse extends Extract<Response, { ok: true }> {
  data: { ahead: number; behind: number; lastSyncAt: number | null;
          pendingItems: number };
}

export const CONTENT_CALLABLE_TYPES: ReadonlySet<ContentMessage['type']> = new Set([
  'get_autofill_candidates', 'get_credentials', 'check_credential', 'blacklist_site',
  'capture_save_login',
] as ContentMessage['type'][]);
