/**
 * Mawidi Demo Scheduler - LocalStorage Utilities
 * Persistent storage functions for booking drafts and user preferences
 */

import type {
  PersistedFormState,
  SchedulerState,
} from "../types/scheduler.types";
import { STORAGE_KEYS, DRAFT_EXPIRATION_MS } from "../config/schedulerConfig";
import { toValidDate } from "./dateValidation";

/**
 * Current schema version for migrations
 */
const SCHEMA_VERSION = "1.0.0";

/**
 * Save booking draft to localStorage
 *
 * @param state - Scheduler state to persist
 * @returns True if save was successful
 */
export function saveBookingDraft(state: Partial<SchedulerState>): boolean {
  if (typeof window === "undefined") {
    return false;
  }

  try {
    const persistedState: PersistedFormState = {
      state,
      timestamp: Date.now(),
      version: SCHEMA_VERSION,
    };

    localStorage.setItem(
      STORAGE_KEYS.BOOKING_DRAFT,
      JSON.stringify(persistedState),
    );

    return true;
  } catch (error) {
    console.error("Failed to save booking draft:", error);
    return false;
  }
}

/**
 * Restore booking draft from localStorage
 *
 * @returns Restored state or null if no valid draft exists
 */
export function restoreBookingDraft(): Partial<SchedulerState> | null {
  if (typeof window === "undefined") {
    return null;
  }

  try {
    const saved = localStorage.getItem(STORAGE_KEYS.BOOKING_DRAFT);

    if (!saved) {
      return null;
    }

    const persisted: PersistedFormState = JSON.parse(saved);

    // Check if draft has expired
    const age = Date.now() - persisted.timestamp;
    if (age > DRAFT_EXPIRATION_MS) {
      clearBookingDraft();
      return null;
    }

    // Check schema version compatibility
    if (persisted.version !== SCHEMA_VERSION) {
      // TODO: Implement migration logic if needed
      clearBookingDraft();
      return null;
    }

    // Restore Date objects from ISO strings with validation
    // Uses shared date validation to prevent epoch date bugs
    persisted.state.selectedDate = toValidDate(persisted.state.selectedDate);

    return persisted.state;
  } catch (error) {
    console.error("Failed to restore booking draft:", error);
    clearBookingDraft();
    return null;
  }
}

/**
 * Clear booking draft from localStorage
 */
export function clearBookingDraft(): void {
  if (typeof window === "undefined") {
    return;
  }

  try {
    localStorage.removeItem(STORAGE_KEYS.BOOKING_DRAFT);
  } catch (error) {
    console.error("Failed to clear booking draft:", error);
  }
}

/**
 * Check if a valid booking draft exists
 *
 * @returns True if valid draft exists
 */
export function hasSavedDraft(): boolean {
  if (typeof window === "undefined") {
    return false;
  }

  try {
    const saved = localStorage.getItem(STORAGE_KEYS.BOOKING_DRAFT);
    if (!saved) {
      return false;
    }

    const persisted: PersistedFormState = JSON.parse(saved);
    const age = Date.now() - persisted.timestamp;

    return age <= DRAFT_EXPIRATION_MS && persisted.version === SCHEMA_VERSION;
  } catch {
    return false;
  }
}

/**
 * Save user's timezone preference
 *
 * @param timezone - IANA timezone identifier
 * @returns True if save was successful
 */
export function saveUserTimezone(timezone: string): boolean {
  if (typeof window === "undefined") {
    return false;
  }

  try {
    localStorage.setItem(STORAGE_KEYS.USER_TIMEZONE, timezone);
    return true;
  } catch (error) {
    console.error("Failed to save user timezone:", error);
    return false;
  }
}

/**
 * Get user's saved timezone preference
 *
 * @returns Saved timezone or null
 */
export function getUserTimezone(): string | null {
  if (typeof window === "undefined") {
    return null;
  }

  try {
    return localStorage.getItem(STORAGE_KEYS.USER_TIMEZONE);
  } catch (error) {
    console.error("Failed to get user timezone:", error);
    return null;
  }
}

/**
 * Clear user's timezone preference
 */
export function clearUserTimezone(): void {
  if (typeof window === "undefined") {
    return;
  }

  try {
    localStorage.removeItem(STORAGE_KEYS.USER_TIMEZONE);
  } catch (error) {
    console.error("Failed to clear user timezone:", error);
  }
}

/**
 * Record last visit timestamp
 */
export function recordLastVisit(): void {
  if (typeof window === "undefined") {
    return;
  }

  try {
    localStorage.setItem(STORAGE_KEYS.LAST_VISIT, Date.now().toString());
  } catch (error) {
    console.error("Failed to record last visit:", error);
  }
}

/**
 * Get last visit timestamp
 *
 * @returns Last visit timestamp or null
 */
export function getLastVisit(): number | null {
  if (typeof window === "undefined") {
    return null;
  }

  try {
    const timestamp = localStorage.getItem(STORAGE_KEYS.LAST_VISIT);
    return timestamp ? parseInt(timestamp, 10) : null;
  } catch (error) {
    console.error("Failed to get last visit:", error);
    return null;
  }
}

/**
 * Check if user is returning (has visited before)
 *
 * @returns True if user has visited before
 */
export function isReturningUser(): boolean {
  return getLastVisit() !== null;
}

/**
 * Get days since last visit
 *
 * @returns Number of days or null if never visited
 */
export function getDaysSinceLastVisit(): number | null {
  const lastVisit = getLastVisit();
  if (!lastVisit) {
    return null;
  }

  const daysSince = Math.floor(
    (Date.now() - lastVisit) / (1000 * 60 * 60 * 24),
  );
  return daysSince;
}

/**
 * Clear all scheduler-related localStorage data
 */
export function clearAllSchedulerData(): void {
  clearBookingDraft();
  clearUserTimezone();

  try {
    localStorage.removeItem(STORAGE_KEYS.LAST_VISIT);
  } catch (error) {
    console.error("Failed to clear last visit:", error);
  }
}

/**
 * Get localStorage usage information
 *
 * @returns Object with usage stats
 */
export function getStorageUsage(): {
  used: number;
  available: number;
  percentage: number;
} {
  if (typeof window === "undefined") {
    return {
      used: 0,
      available: 0,
      percentage: 0,
    };
  }

  try {
    // Estimate localStorage size (approximate)
    let used = 0;
    for (const key in localStorage) {
      if (localStorage.hasOwnProperty(key)) {
        used += localStorage[key].length + key.length;
      }
    }

    // Most browsers allow ~5-10MB, we'll assume 5MB
    const available = 5 * 1024 * 1024; // 5MB in bytes
    const percentage = (used / available) * 100;

    return {
      used,
      available,
      percentage: Math.round(percentage * 100) / 100,
    };
  } catch {
    return {
      used: 0,
      available: 0,
      percentage: 0,
    };
  }
}

/**
 * Check if localStorage is available and functional
 *
 * @returns True if localStorage is available
 */
export function isLocalStorageAvailable(): boolean {
  if (typeof window === "undefined") {
    return false;
  }

  try {
    const testKey = "__mawidi_storage_test__";
    localStorage.setItem(testKey, "test");
    localStorage.removeItem(testKey);
    return true;
  } catch {
    return false;
  }
}

/**
 * Safely get item from localStorage with error handling
 *
 * @param key - Storage key
 * @param defaultValue - Default value if key doesn't exist
 * @returns Stored value or default
 */
export function safeGetItem<T>(key: string, defaultValue: T): T {
  if (typeof window === "undefined") {
    return defaultValue;
  }

  try {
    const item = localStorage.getItem(key);
    if (item === null) {
      return defaultValue;
    }

    return JSON.parse(item) as T;
  } catch (error) {
    console.error(`Failed to get item ${key} from localStorage:`, error);
    return defaultValue;
  }
}

/**
 * Safely set item in localStorage with error handling
 *
 * @param key - Storage key
 * @param value - Value to store
 * @returns True if successful
 */
export function safeSetItem<T>(key: string, value: T): boolean {
  if (typeof window === "undefined") {
    return false;
  }

  try {
    localStorage.setItem(key, JSON.stringify(value));
    return true;
  } catch (error) {
    console.error(`Failed to set item ${key} in localStorage:`, error);

    // Check if quota exceeded
    if (error instanceof DOMException && error.name === "QuotaExceededError") {
      console.warn("LocalStorage quota exceeded. Consider clearing old data.");
    }

    return false;
  }
}

/**
 * Safely remove item from localStorage
 *
 * @param key - Storage key to remove
 */
export function safeRemoveItem(key: string): void {
  if (typeof window === "undefined") {
    return;
  }

  try {
    localStorage.removeItem(key);
  } catch (error) {
    console.error(`Failed to remove item ${key} from localStorage:`, error);
  }
}

/**
 * Export all scheduler data as JSON (for backup/debugging)
 *
 * @returns JSON string of all scheduler data
 */
export function exportSchedulerData(): string {
  if (typeof window === "undefined") {
    return "{}";
  }

  try {
    const data = {
      bookingDraft: localStorage.getItem(STORAGE_KEYS.BOOKING_DRAFT),
      userTimezone: localStorage.getItem(STORAGE_KEYS.USER_TIMEZONE),
      lastVisit: localStorage.getItem(STORAGE_KEYS.LAST_VISIT),
      exportedAt: new Date().toISOString(),
      version: SCHEMA_VERSION,
    };

    return JSON.stringify(data, null, 2);
  } catch (error) {
    console.error("Failed to export scheduler data:", error);
    return "{}";
  }
}

/**
 * Import scheduler data from JSON (for restore/debugging)
 *
 * @param jsonString - JSON string to import
 * @returns True if import was successful
 */
export function importSchedulerData(jsonString: string): boolean {
  if (typeof window === "undefined") {
    return false;
  }

  try {
    const data = JSON.parse(jsonString);

    if (data.bookingDraft) {
      localStorage.setItem(STORAGE_KEYS.BOOKING_DRAFT, data.bookingDraft);
    }

    if (data.userTimezone) {
      localStorage.setItem(STORAGE_KEYS.USER_TIMEZONE, data.userTimezone);
    }

    if (data.lastVisit) {
      localStorage.setItem(STORAGE_KEYS.LAST_VISIT, data.lastVisit);
    }

    return true;
  } catch (error) {
    console.error("Failed to import scheduler data:", error);
    return false;
  }
}

/**
 * Clean up expired drafts and old data
 *
 * @returns Number of items cleaned
 */
export function cleanupExpiredData(): number {
  if (typeof window === "undefined") {
    return 0;
  }

  let cleaned = 0;

  try {
    // Check booking draft
    if (hasSavedDraft() === false) {
      const draft = localStorage.getItem(STORAGE_KEYS.BOOKING_DRAFT);
      if (draft) {
        clearBookingDraft();
        cleaned++;
      }
    }

    // Clean up any other old Mawidi-related data
    for (const key in localStorage) {
      if (
        key.startsWith("mawidi_") &&
        !(Object.values(STORAGE_KEYS) as string[]).includes(key)
      ) {
        localStorage.removeItem(key);
        cleaned++;
      }
    }
  } catch (error) {
    console.error("Failed to cleanup expired data:", error);
  }

  return cleaned;
}

/**
 * Get draft age in hours
 *
 * @returns Age in hours or null if no draft
 */
export function getDraftAge(): number | null {
  if (typeof window === "undefined") {
    return null;
  }

  try {
    const saved = localStorage.getItem(STORAGE_KEYS.BOOKING_DRAFT);
    if (!saved) {
      return null;
    }

    const persisted: PersistedFormState = JSON.parse(saved);
    const ageMs = Date.now() - persisted.timestamp;
    return Math.floor(ageMs / (1000 * 60 * 60));
  } catch {
    return null;
  }
}

// ============================================================================
// ALIASES FOR BACKWARD COMPATIBILITY
// ============================================================================

/**
 * Alias for saveBookingDraft
 */
export const saveBookingToStorage = saveBookingDraft;

/**
 * Alias for restoreBookingDraft
 */
export const getBookingFromStorage = restoreBookingDraft;

/**
 * Alias for clearBookingDraft
 */
export const clearBookingFromStorage = clearBookingDraft;
