import { readLocalJson, removeLocalValue, writeLocalJson } from './safeStorage';
import { captureCaught } from '@/lib/observability';
import { clearWishlistQueue } from './wishlistQueue';
import { getCsrfToken } from '@/lib/csrf';

const VISITED_DEAL_KEY = 'multideal:offline:visited-deal:v1';
const WALLET_QR_KEY = 'multideal:offline:wallet-qr:v1';
const INSTALL_COOLDOWN_KEY = 'multideal:install-sheet:cooldown:v1';
const INSTALL_COOLDOWN_MS = 1000 * 60 * 60 * 24 * 3;

export interface OfflineVisitedDealSnapshot {
  dealId: string;
  title: string;
  vendorName: string;
  href: string;
  updatedAt: number;
}

export interface OfflineQrVoucherSnapshot {
  voucherId: string;
  qrPngUrl: string | null;
  expiresAt?: string;
}

export interface OfflineWalletQrSnapshot {
  purchaseId: string;
  dealTitle: string;
  businessName: string;
  purchaseShortId?: string;
  qrPngUrl: string;
  expiresAt?: string;
  vouchers: OfflineQrVoucherSnapshot[];
  updatedAt: number;
}

function isVisitedDealSnapshot(value: unknown): value is OfflineVisitedDealSnapshot {
  if (!value || typeof value !== 'object') return false;
  const candidate = value as Record<string, unknown>;
  return (
    typeof candidate.dealId === 'string' &&
    typeof candidate.title === 'string' &&
    typeof candidate.vendorName === 'string' &&
    typeof candidate.href === 'string' &&
    typeof candidate.updatedAt === 'number'
  );
}

function isQrVoucherSnapshot(value: unknown): value is OfflineQrVoucherSnapshot {
  if (!value || typeof value !== 'object') return false;
  const candidate = value as Record<string, unknown>;
  return (
    typeof candidate.voucherId === 'string' &&
    (candidate.qrPngUrl === null || typeof candidate.qrPngUrl === 'string') &&
    (candidate.expiresAt === undefined || typeof candidate.expiresAt === 'string')
  );
}

function isWalletQrSnapshot(value: unknown): value is OfflineWalletQrSnapshot {
  if (!value || typeof value !== 'object') return false;
  const candidate = value as Record<string, unknown>;
  return (
    typeof candidate.purchaseId === 'string' &&
    typeof candidate.dealTitle === 'string' &&
    typeof candidate.businessName === 'string' &&
    typeof candidate.qrPngUrl === 'string' &&
    typeof candidate.updatedAt === 'number' &&
    Array.isArray(candidate.vouchers) &&
    candidate.vouchers.every(isQrVoucherSnapshot) &&
    (candidate.purchaseShortId === undefined || typeof candidate.purchaseShortId === 'string') &&
    (candidate.expiresAt === undefined || typeof candidate.expiresAt === 'string')
  );
}

export function writeVisitedDealSnapshot(snapshot: OfflineVisitedDealSnapshot): void {
  writeLocalJson(VISITED_DEAL_KEY, snapshot);
}

export function readVisitedDealSnapshot(): OfflineVisitedDealSnapshot | null {
  return readLocalJson<OfflineVisitedDealSnapshot | null>(
    VISITED_DEAL_KEY,
    null,
    (value): value is OfflineVisitedDealSnapshot | null =>
      value === null || isVisitedDealSnapshot(value),
  );
}

export function writeWalletQrSnapshot(snapshot: OfflineWalletQrSnapshot): void {
  const owner = getCsrfToken();
  if (!owner) return;
  writeLocalJson(WALLET_QR_KEY, { ...snapshot, owner });
}

function isWalletQrSnapshotExpired(snapshot: OfflineWalletQrSnapshot): boolean {
  if (!snapshot.expiresAt) return false;
  const expiresAt = Date.parse(snapshot.expiresAt);
  return Number.isFinite(expiresAt) && expiresAt <= Date.now();
}

export function readWalletQrSnapshot(): OfflineWalletQrSnapshot | null {
  const snapshot = readLocalJson<OfflineWalletQrSnapshot | null>(
    WALLET_QR_KEY,
    null,
    (value): value is OfflineWalletQrSnapshot | null => value === null || isWalletQrSnapshot(value),
  );
  if (snapshot && isWalletQrSnapshotExpired(snapshot)) {
    removeLocalValue(WALLET_QR_KEY);
    return null;
  }
  const owner = getCsrfToken();
  const snapshotOwner =
    snapshot && (snapshot as OfflineWalletQrSnapshot & { owner?: unknown }).owner;
  if (snapshot && (typeof snapshotOwner !== 'string' || !owner || snapshotOwner !== owner)) {
    removeLocalValue(WALLET_QR_KEY);
    return null;
  }
  return snapshot;
}

export function removeWalletQrSnapshot(purchaseId: string): void {
  if (readWalletQrSnapshot()?.purchaseId === purchaseId) {
    removeLocalValue(WALLET_QR_KEY);
  }
}

export function clearOfflineContinuitySnapshots(): void {
  removeLocalValue(VISITED_DEAL_KEY);
  removeLocalValue(WALLET_QR_KEY);
  clearWishlistQueue();
}

export function isStandaloneDisplayMode(): boolean {
  if (typeof window === 'undefined') return false;
  try {
    if (window.matchMedia?.('(display-mode: standalone)').matches) return true;
  } catch (err) {
    captureCaught(err, {
      scope: 'lib.offline.offlineContinuity.isStandaloneDisplayMode',
      severity: 'warning',
    });
  }
  const nav = window.navigator as Navigator & { standalone?: boolean };
  return nav.standalone === true;
}

export function installSheetOnCooldown(now = Date.now()): boolean {
  const expiresAt = readLocalJson<number | null>(
    INSTALL_COOLDOWN_KEY,
    null,
    (value): value is number | null =>
      value === null || (typeof value === 'number' && Number.isFinite(value)),
  );
  return expiresAt !== null && expiresAt > now;
}

export function startInstallSheetCooldown(now = Date.now()): void {
  writeLocalJson(INSTALL_COOLDOWN_KEY, now + INSTALL_COOLDOWN_MS);
}
