// src/tests/utils/mockFactories.ts
import { UserProfile, User, Flyer, Store, SuggestedCorrection, Brand, FlyerItem, MasterGroceryItem, ShoppingList, ShoppingListItem, Achievement, UserAchievement, Budget, SpendingByCategory, Recipe, RecipeComment, ActivityLogItem, DietaryRestriction, Appliance, Notification, UnmatchedFlyerItem, AdminUserView, WatchedItemDeal, LeaderboardUser, UserWithPasswordHash, Profile } from '../../types';

/**
 * Creates a mock UserProfile object for use in tests, ensuring type safety.
 *
 * @param overrides - An object containing properties to override the default mock values.
 *                    This allows for easy customization of the mock user for specific test cases.
 *                    For example: `createMockUserProfile({ role: 'admin', points: 500 })`
 * @returns A complete and type-safe UserProfile object.
 */
export const createMockUserProfile = (overrides: Partial<UserProfile & { user: Partial<User> }> = {}): UserProfile => {
  const userId = overrides.user_id ?? `user-${Math.random().toString(36).substring(2, 9)}`;

  const defaultProfile: UserProfile = {
    user_id: userId,
    role: 'user',
    points: 0,
    full_name: 'Test User',
    avatar_url: null,
    preferences: {},
    address: null,
    user: {
      user_id: userId,
      email: `${userId}@example.com`,
      ...overrides.user, // Apply nested user overrides
    },
  };

  return { ...defaultProfile, ...overrides };
};

/**
 * Creates a mock Flyer object for use in tests, ensuring type safety.
 *
 * @param overrides - An object containing properties to override the default mock values,
 *                    including nested properties for the `store`.
 *                    e.g., `createMockFlyer({ item_count: 50, store: { name: 'Walmart' } })`
 * @returns A complete and type-safe Flyer object.
 */
export const createMockFlyer = (overrides: Partial<Flyer & { store: Partial<Store> }> = {}): Flyer => {
  const flyerId = overrides.flyer_id ?? Math.floor(Math.random() * 1000);
  const storeId = overrides.store?.store_id ?? Math.floor(Math.random() * 100);

  const defaultFlyer: Flyer = {
    flyer_id: flyerId,
    created_at: new Date().toISOString(),
    file_name: `flyer-${flyerId}.jpg`,
    image_url: `/flyer-images/flyer-${flyerId}.jpg`,
    icon_url: `/flyer-images/icons/icon-flyer-${flyerId}.webp`,
    checksum: `checksum-${flyerId}`,
    store_id: storeId,
    valid_from: new Date().toISOString().split('T')[0],
    valid_to: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0], // 7 days from now
    store_address: '123 Main St, Anytown, USA',
    item_count: Math.floor(Math.random() * 100) + 10,
    uploaded_by: null,
    store: {
      store_id: storeId,
      created_at: new Date().toISOString(),
      name: 'Mock Store',
      logo_url: null,
    },
  };

  // Deep merge the store object and then merge the top-level properties.
  return { ...defaultFlyer, ...overrides, store: { ...defaultFlyer.store, ...overrides.store } as Store };
};

/**
 * Creates a mock SuggestedCorrection object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe SuggestedCorrection object.
 */
export const createMockSuggestedCorrection = (overrides: Partial<SuggestedCorrection> = {}): SuggestedCorrection => {
  const defaultCorrection: SuggestedCorrection = {
    suggested_correction_id: Math.floor(Math.random() * 1000),
    flyer_item_id: Math.floor(Math.random() * 10000),
    user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
    correction_type: 'price',
    suggested_value: '$9.99',
    status: 'pending',
    created_at: new Date().toISOString(),
  };

  return { ...defaultCorrection, ...overrides };
};

/**
 * Creates a mock Brand object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe Brand object.
 */
export const createMockBrand = (overrides: Partial<Brand> = {}): Brand => {
  const brandId = overrides.brand_id ?? Math.floor(Math.random() * 100);

  const defaultBrand: Brand = {
    brand_id: brandId,
    name: `Brand ${brandId}`,
    logo_url: null,
    store_id: null,
    store_name: null,
  };

  return { ...defaultBrand, ...overrides };
};

/**
 * Creates a mock FlyerItem object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe FlyerItem object.
 */
export const createMockFlyerItem = (overrides: Partial<FlyerItem> = {}): FlyerItem => {
  const defaultItem: FlyerItem = {
    flyer_item_id: Math.floor(Math.random() * 10000),
    flyer_id: Math.floor(Math.random() * 1000),
    created_at: new Date().toISOString(),
    item: 'Mock Item',
    price_display: '$1.99',
    price_in_cents: 199,
    quantity: 'each',
    view_count: 0,
    click_count: 0,
    updated_at: new Date().toISOString(),
  };

  return { ...defaultItem, ...overrides };
};

/**
 * Creates a mock Recipe object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe Recipe object.
 */
export const createMockRecipe = (overrides: Partial<Recipe> = {}): Recipe => {
  const recipeId = overrides.recipe_id ?? Math.floor(Math.random() * 1000);

  const defaultRecipe: Recipe = {
    recipe_id: recipeId,
    user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
    name: `Mock Recipe ${recipeId}`,
    description: 'A delicious mock recipe.',
    instructions: '1. Mock the ingredients. 2. Mock the cooking. 3. Enjoy!',
    avg_rating: Math.random() * 5,
    rating_count: Math.floor(Math.random() * 100),
    fork_count: Math.floor(Math.random() * 20),
    status: 'public',
    created_at: new Date().toISOString(),
    prep_time_minutes: 15,
    cook_time_minutes: 30,
    servings: 4,
  };

  return { ...defaultRecipe, ...overrides };
};

/**
 * Creates a mock RecipeComment object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe RecipeComment object.
 */
export const createMockRecipeComment = (overrides: Partial<RecipeComment> = {}): RecipeComment => {
  const defaultComment: RecipeComment = {
    recipe_comment_id: Math.floor(Math.random() * 10000),
    recipe_id: Math.floor(Math.random() * 1000),
    user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
    content: 'This is a mock comment.',
    status: 'visible',
    created_at: new Date().toISOString(),
    user_full_name: 'Mock User', // This was correct
    user_avatar_url: undefined,
  };

  return { ...defaultComment, ...overrides };
};

/**
 * Creates a mock ActivityLogItem object for use in tests.
 * This factory handles the discriminated union nature of the ActivityLogItem type.
 * By default, it creates a 'flyer_processed' log item. You can override the 'action'
 * and 'details' to create other types of log items.
 *
 * @param overrides - An object containing properties to override the default mock values.
 *   e.g., `createMockActivityLogItem({ action: 'user_registered', details: { full_name: 'New User' } })`
 * @returns A complete and type-safe ActivityLogItem object.
 */
export const createMockActivityLogItem = (overrides: Partial<ActivityLogItem> = {}): ActivityLogItem => {
  const action = overrides.action ?? 'flyer_processed';

  const baseLog = {
    activity_log_id: Math.floor(Math.random() * 10000),
    user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
    created_at: new Date().toISOString(),
  };

  let specificLog: ActivityLogItem;

  // Create a default log based on the action, which can then be overridden.
  switch (action) {
    case 'recipe_created':
      specificLog = {
        ...baseLog,
        action: 'recipe_created',
        display_text: 'Created a new recipe: Mock Recipe.',
        icon: 'chef-hat',
        details: { recipe_id: 1, recipe_name: 'Mock Recipe' },
      };
      break;
    case 'user_registered':
      specificLog = {
        ...baseLog,
        action: 'user_registered',
        display_text: 'A new user has registered.',
        icon: 'user-plus',
        details: { full_name: 'New Mock User' },
      };
      break;
    case 'list_shared':
      specificLog = {
        ...baseLog,
        action: 'list_shared',
        display_text: 'A shopping list was shared.',
        icon: 'share-2',
        details: { list_name: 'Mock List', shopping_list_id: 1, shared_with_name: 'Another User' },
      };
      break;
    case 'flyer_processed':
    default:
      specificLog = {
        ...baseLog,
        action: 'flyer_processed',
        display_text: 'Processed a new flyer for Mock Store.',
        icon: 'file-check',
        details: { flyer_id: 1, store_name: 'Mock Store' },
      };
      break;
  }

  // Merge the generated log with any specific overrides provided.
  // This allows for deep merging of the 'details' object.
  return { ...specificLog, ...overrides, details: { ...specificLog.details, ...overrides.details } } as ActivityLogItem;
};

/**
 * Creates a mock Achievement object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe Achievement object.
 */
export const createMockAchievement = (overrides: Partial<Achievement> = {}): Achievement => {
  const defaultAchievement: Achievement = {
    achievement_id: Math.floor(Math.random() * 100),
    name: 'Mock Achievement',
    description: 'A great accomplishment.',
    icon: 'star',
    points_value: 10,
  };
  return { ...defaultAchievement, ...overrides };
};

/**
 * Creates a mock object representing a joined UserAchievement and Achievement for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe object representing the joined achievement data.
 */
export const createMockUserAchievement = (overrides: Partial<UserAchievement & Achievement> = {}): UserAchievement & Achievement => {
  const achievementId = overrides.achievement_id ?? Math.floor(Math.random() * 100);
  const defaultUserAchievement: UserAchievement & Achievement = {
    user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
    achievement_id: achievementId,
    achieved_at: new Date().toISOString(),
    // from Achievement
    name: 'Mock User Achievement',
    description: 'An achievement someone earned.',
    icon: 'award',
    points_value: 20,
  };
  return { ...defaultUserAchievement, ...overrides };
};

/**
 * Creates a mock Budget object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe Budget object.
 */
export const createMockBudget = (overrides: Partial<Budget> = {}): Budget => {
  const defaultBudget: Budget = {
    budget_id: Math.floor(Math.random() * 100),
    user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
    name: 'Monthly Groceries',
    amount_cents: 50000,
    period: 'monthly',
    start_date: new Date().toISOString().split('T')[0],
  };
  return { ...defaultBudget, ...overrides };
};

/**
 * Creates a mock SpendingByCategory object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe SpendingByCategory object.
 */
export const createMockSpendingByCategory = (overrides: Partial<SpendingByCategory> = {}): SpendingByCategory => {
  const defaultSpending: SpendingByCategory = {
    category_id: Math.floor(Math.random() * 20) + 1,
    category_name: 'Produce',
    total_spent_cents: Math.floor(Math.random() * 20000) + 1000,
  };
  return { ...defaultSpending, ...overrides };
};

/**
 * Creates a mock MasterGroceryItem object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe MasterGroceryItem object.
 */
export const createMockMasterGroceryItem = (overrides: Partial<MasterGroceryItem> = {}): MasterGroceryItem => {
  const defaultItem: MasterGroceryItem = {
    master_grocery_item_id: Math.floor(Math.random() * 10000),
    created_at: new Date().toISOString(),
    name: 'Mock Master Item',
    category_id: 1,
    category_name: 'Pantry & Dry Goods',
  };

  return { ...defaultItem, ...overrides };
};

/**
 * Creates a mock ShoppingList object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe ShoppingList object.
 */
export const createMockShoppingList = (overrides: Partial<ShoppingList> = {}): ShoppingList => {
  const defaultList: ShoppingList = {
    shopping_list_id: Math.floor(Math.random() * 100),
    user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
    name: 'My Mock List',
    created_at: new Date().toISOString(),
    items: [],
  };

  return { ...defaultList, ...overrides };
};

/**
 * Creates a mock ShoppingListItem object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe ShoppingListItem object.
 */
export const createMockShoppingListItem = (overrides: Partial<ShoppingListItem> = {}): ShoppingListItem => {
  const defaultItem: ShoppingListItem = {
    shopping_list_item_id: Math.floor(Math.random() * 100000),
    shopping_list_id: Math.floor(Math.random() * 100),
    custom_item_name: 'Mock Shopping List Item',
    quantity: 1,
    is_purchased: false,
    added_at: new Date().toISOString(),
  };

  return { ...defaultItem, ...overrides };
};

/**
 * Creates a mock DietaryRestriction object for testing.
 * @param overrides - Optional properties to override the defaults.
 * @returns A mock DietaryRestriction object.
 */
export const createMockDietaryRestriction = (overrides: Partial<DietaryRestriction> = {}): DietaryRestriction => {
  return {
    dietary_restriction_id: 1,
    name: 'Vegetarian',
    type: 'diet',
    ...overrides,
  };
};

/**
 * Creates a mock UserWithPasswordHash object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe UserWithPasswordHash object.
 */
export const createMockUserWithPasswordHash = (overrides: Partial<UserWithPasswordHash> = {}): UserWithPasswordHash => {
  const userId = overrides.user_id ?? `user-${Math.random().toString(36).substring(2, 9)}`;

  const defaultUser: UserWithPasswordHash = {
    user_id: userId,
    email: `${userId}@example.com`,
    password_hash: 'hashed_password',
    failed_login_attempts: 0,
    last_failed_login: null,
  };

  return { ...defaultUser, ...overrides };
};

/**
 * Creates a mock Profile object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe Profile object.
 */
export const createMockProfile = (overrides: Partial<Profile> = {}): Profile => {
  const userId = overrides.user_id ?? `user-${Math.random().toString(36).substring(2, 9)}`;

  const defaultProfile: Profile = {
    user_id: userId,
    updated_at: new Date().toISOString(),
    full_name: 'Mock Profile User',
    avatar_url: null,
    address_id: null,
    points: 0,
    role: 'user',
    preferences: {},
  };

  return { ...defaultProfile, ...overrides };
};

/**
 * Creates a mock WatchedItemDeal object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe WatchedItemDeal object.
 */
export const createMockWatchedItemDeal = (overrides: Partial<WatchedItemDeal> = {}): WatchedItemDeal => {
  const defaultDeal: WatchedItemDeal = {
    master_item_id: Math.floor(Math.random() * 1000),
    item_name: 'Mock Deal Item',
    best_price_in_cents: Math.floor(Math.random() * 1000) + 100,
    store_name: 'Mock Store',
    flyer_id: Math.floor(Math.random() * 100),
    valid_to: new Date(Date.now() + 5 * 24 * 60 * 60 * 1000).toISOString(), // 5 days from now
  };

  return { ...defaultDeal, ...overrides };
};

/**
 * Creates a mock LeaderboardUser object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe LeaderboardUser object.
 */
export const createMockLeaderboardUser = (overrides: Partial<LeaderboardUser> = {}): LeaderboardUser => {
  const userId = overrides.user_id ?? `user-${Math.random().toString(36).substring(2, 9)}`;

  const defaultUser: LeaderboardUser = {
    user_id: userId,
    full_name: 'Leaderboard User',
    avatar_url: null,
    points: Math.floor(Math.random() * 1000),
    rank: String(Math.floor(Math.random() * 100) + 1),
  };

  return { ...defaultUser, ...overrides };
};

/**
 * Creates a mock UnmatchedFlyerItem object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe UnmatchedFlyerItem object.
 */
export const createMockUnmatchedFlyerItem = (overrides: Partial<UnmatchedFlyerItem> = {}): UnmatchedFlyerItem => {
  const defaultItem: UnmatchedFlyerItem = {
    unmatched_flyer_item_id: Math.floor(Math.random() * 1000),
    status: 'pending',
    created_at: new Date().toISOString(),
    flyer_item_id: Math.floor(Math.random() * 10000),
    flyer_item_name: 'Mystery Product',
    price_display: '$?.??',
    flyer_id: Math.floor(Math.random() * 100),
    store_name: 'Random Store',
  };

  return { ...defaultItem, ...overrides };
};

/**
 * Creates a mock AdminUserView object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe AdminUserView object.
 */
export const createMockAdminUserView = (overrides: Partial<AdminUserView> = {}): AdminUserView => {
  const userId = overrides.user_id ?? `user-${Math.random().toString(36).substring(2, 9)}`;

  const defaultUserView: AdminUserView = {
    user_id: userId,
    email: `${userId}@example.com`,
    created_at: new Date().toISOString(),
    role: 'user',
    full_name: 'Mock User',
    avatar_url: null,
  };

  return { ...defaultUserView, ...overrides };
};

/**
 * Creates a mock Notification object for use in tests.
 * @param overrides - An object containing properties to override the default mock values.
 * @returns A complete and type-safe Notification object.
 */
export const createMockNotification = (overrides: Partial<Notification> = {}): Notification => {
  const defaultNotification: Notification = {
    notification_id: Math.floor(Math.random() * 1000),
    user_id: `user-${Math.random().toString(36).substring(2, 9)}`,
    content: 'This is a mock notification.',
    link_url: null,
    is_read: false,
    created_at: new Date().toISOString(),
  };

  return { ...defaultNotification, ...overrides };
};

export const createMockAppliance = (overrides: Partial<Appliance> = {}): Appliance => {
  return {
    appliance_id: 1,
    name: 'Oven',
    ...overrides,
  };
};