// src/client/entities/blacklist.ts
// Blacklist entity - Pinia store for blacklist management with Refetch Strategy

import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import { blacklistRepository, type BlacklistEntryResponse, type BlacklistPendingEntryResponse } from '../shared/api/repositories/BlacklistRepository';
import type { BlacklistEntry, BlacklistCreateRequest, BlacklistUpdateRequest, BlacklistUnifiedEntry } from '@shared/contracts/blacklist';
import { calculateUnifiedList } from './blacklist/model/unifiedList';
import { patchEntries, patchPendingEntries, patchEntry, removeEntry as removeEntryHelper } from './blacklist/model/mergeHelpers';
import { EVENTS } from '@shared/contracts/events';
import { socketService } from '../shared/api/SocketService';

export const useBlacklistStore = defineStore('blacklist', () => {
  // State
  const entries = ref<BlacklistEntry[]>([]);
  const pendingEntries = ref<BlacklistPendingEntryResponse[]>([]);
  const loading = ref(false);
  const error = ref<string | null>(null);
  const searchQuery = ref<string>('');
  const socketBound = ref(false);
  const socketUnsubscribers = ref<(() => void)[]>([]);

  // Computed
  const approvedEntries = computed(() => entries.value.filter(e => e.isApproved));
  const hasPendingEntries = computed(() => pendingEntries.value.length > 0);

  /**
   * Display List - объединяет записи с дедупликацией
   * Если pending запись имеет targetId, оригинальная запись скрывается
   */
  const displayList = computed(() => {
    // Собираем все ID оригинальных записей, которые редактируются
    const targetIds = new Set(
      pendingEntries.value
        .filter((p: BlacklistPendingEntryResponse) => p.targetId !== null)
        .map((p: BlacklistPendingEntryResponse) => p.targetId!)
    );

    // Фильтруем записи: оставляем только те, у которых нет pending версии
    const filteredEntries = entries.value.filter((e: BlacklistEntry) => !targetIds.has(e.id));

    // Добавляем pending записи в общий список
    const pendingAsEntries = pendingEntries.value.map((p: BlacklistPendingEntryResponse) => ({
      id: p.id,
      name: p.name,
      phone: p.phone,
      bookingEngineCheck: p.bookingEngineCheck,
      comment: p.comment,
      isApproved: false,
      createdBy: p.createdBy,
      createdAt: p.createdAt,
      updatedAt: p.updatedAt,
      archivedAt: null,
    } as BlacklistEntry));

    // Объединяем и сортируем по createdAt
    return [...filteredEntries, ...pendingAsEntries].sort((a, b) =>
      new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime()
    );
  });

  /**
   * Unified List - объединяет записи с сохранением информации об изменениях
   * Для pending записей с targetId: заменяет оригинал и добавляет флаги isModified/originalData
   * Для pending записей без targetId: добавляет как новые с флагом isNew
   * Для pending записей со статусом to_delete: добавляет флаг isPendingDelete
   */
  const unifiedList = computed<BlacklistUnifiedEntry[]>(() => {
    return calculateUnifiedList(entries.value, pendingEntries.value);
  });

  /**
   * Fetch all blacklist entries
   */
  async function fetchAll(status?: 'pending' | 'approved') {
    loading.value = true;
    error.value = null;
    try {
      const data = await blacklistRepository.getAll(status);
      // Smart Merge: update entries without resetting entire array
      if (status === 'pending') {
        // Для pending записей обновляем pendingEntries
        // API должен возвращать pending записи с полем targetId
        const pendingData = data.map((entry: BlacklistEntryResponse) => ({
          id: entry.id,
          name: entry.name,
          phone: entry.phone,
          bookingEngineCheck: entry.bookingEngineCheck,
          comment: entry.comment,
          status: 'pending' as const,
          targetId: null, // API должен предоставлять это поле
          createdBy: entry.createdBy,
          creatorName: null, // Будет заполнено API
          reviewedBy: null,
          reviewedAt: null,
          rejectionReason: null,
          createdAt: entry.createdAt,
          updatedAt: entry.updatedAt,
        } as BlacklistPendingEntryResponse));
        smartMergePendingEntries(pendingData);
      } else {
        smartMergeEntries(data);
      }
    } catch (err: any) {
      error.value = err.message || 'Не удалось загрузить записи черного списка';
      console.error('Error fetching blacklist entries:', err);
    } finally {
      loading.value = false;
    }
  }

  /**
   * Fetch only pending entries
   */
  async function fetchPending() {
    loading.value = true;
    error.value = null;
    try {
      const data = await blacklistRepository.getPending();
      // API возвращает BlacklistPendingEntryResponse с полем targetId
      smartMergePendingEntries(data);
    } catch (err: any) {
      error.value = err.message || 'Не удалось загрузить записи на согласовании';
      console.error('Error fetching pending entries:', err);
    } finally {
      loading.value = false;
    }
  }

  /**
   * Create new blacklist entry
   */
  async function create(data: BlacklistCreateRequest) {
    loading.value = true;
    error.value = null;
    try {
      await blacklistRepository.create(data);

      // FORCE REFRESH IMMEDIATELY
      await Promise.all([
        fetchAll(),
        fetchPending()
      ]);
    } catch (err: any) {
      error.value = err.message || 'Не удалось создать запись';
      console.error('Error creating blacklist entry:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  }

  /**
   * Update existing blacklist entry
   */
  async function update(id: string, data: BlacklistUpdateRequest) {
    loading.value = true;
    error.value = null;
    try {
      await blacklistRepository.update(id, data);

      // FORCE REFRESH IMMEDIATELY
      await Promise.all([
        fetchAll(),
        fetchPending()
      ]);
    } catch (err: any) {
      error.value = err.message || 'Не удалось обновить запись';
      console.error('Error updating blacklist entry:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  }

  /**
   * Delete blacklist entry
   */
  async function deleteEntry(id: string) {
    loading.value = true;
    error.value = null;
    try {
      await blacklistRepository.deleteEntry(id);

      // FORCE REFRESH IMMEDIATELY
      await Promise.all([
        fetchAll(),
        fetchPending()
      ]);
    } catch (err: any) {
      error.value = err.message || 'Не удалось удалить запись';
      console.error('Error deleting blacklist entry:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  }


  /**
   * Approve single pending entry (ADMIN only)
   */
  async function approveEntry(id: string) {
    loading.value = true;
    error.value = null;
    try {
      await blacklistRepository.approveEntry(id);

      // FORCE REFRESH IMMEDIATELY
      await Promise.all([
        fetchAll(),
        fetchPending()
      ]);
    } catch (err: any) {
      error.value = err.message || 'Не удалось согласовать запись';
      console.error('Error approving entry:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  }

  /**
   * Reject single pending entry (ADMIN only)
   */
  async function rejectEntry(id: string) {
    loading.value = true;
    error.value = null;
    try {
      await blacklistRepository.rejectEntry(id);

      // FORCE REFRESH IMMEDIATELY
      await Promise.all([
        fetchAll(),
        fetchPending()
      ]);
    } catch (err: any) {
      error.value = err.message || 'Не удалось отклонить запись';
      console.error('Error rejecting entry:', err);
      throw err;
    } finally {
      loading.value = false;
    }
  }

  /**
   * Smart Merge: update entries array without resetting
   * Preserves UI state (scroll position, filters, etc.)
   */
  function smartMergeEntries(newEntries: BlacklistEntry[]) {
    entries.value = patchEntries(entries.value, newEntries);
  }

  /**
   * Smart Merge: update pending entries array
   */
  function smartMergePendingEntries(newEntries: BlacklistPendingEntryResponse[]) {
    pendingEntries.value = patchPendingEntries(pendingEntries.value, newEntries);
  }

  /**
   * Smart Merge: update single entry
   * Correctly handles pending entries (with targetId or status) vs approved entries
   */
  function smartMergeEntry(entry: BlacklistEntry & { targetId?: string | null; status?: string; creatorName?: string | null }) {
    const result = patchEntry(entries.value, pendingEntries.value, entry);
    entries.value = result.entries;
    pendingEntries.value = result.pendingEntries;
  }

  /**
   * Remove entry from state
   * Removes from both entries and pendingEntries arrays
   * For pendingEntries, removes by id OR targetId to handle delete requests
   */
  function removeEntry(id: string) {
    const result = removeEntryHelper(entries.value, pendingEntries.value, id);
    entries.value = result.entries;
    pendingEntries.value = result.pendingEntries;
  }

  /**
    * Get entry by ID
    */
  function getEntryById(id: string): BlacklistEntry | undefined {
    return entries.value.find((e: BlacklistEntry) => e.id === id);
  }

  /**
     * Set search query for filtering
     */
  function setSearchQuery(query: string) {
    searchQuery.value = query;
  }

  /**
   * Universal handler for ANY external change.
   * Instead of complex merging, we simply refetch the latest state from the server.
   * This ensures 100% consistency and avoids "ghost" entries.
   */
  async function handleExternalChange() {
    console.log('[BlacklistStore] External change detected. Refreshing data...');
    // Fetch both lists to ensure consistency between "Approved" and "Pending" tabs
    await Promise.all([
      fetchAll(),
      fetchPending()
    ]);
  }

  function bindSocketEvents() {
    if (socketBound.value) return;

    const unsubUpdated = socketService.subscribe(EVENTS.BLACKLIST_UPDATED, handleExternalChange);
    const unsubCreated = socketService.subscribe(EVENTS.BLACKLIST_CREATED, handleExternalChange);
    const unsubDeleted = socketService.subscribe(EVENTS.BLACKLIST_DELETED, handleExternalChange);

    socketUnsubscribers.value = [unsubUpdated, unsubCreated, unsubDeleted];
    socketBound.value = true;
    console.log('[BlacklistStore] Socket events bound (Refetch Strategy)');
  }

  function unbindSocketEvents() {
    if (!socketBound.value) return;

    // Call all unsubscribe functions
    socketUnsubscribers.value.forEach(unsub => unsub());
    socketUnsubscribers.value = [];

    socketBound.value = false;
    console.log('[BlacklistStore] Socket events unbound');
  }

  return {
    // State
    entries,
    pendingEntries,
    loading,
    error,
    searchQuery,
    // Computed
    approvedEntries,
    hasPendingEntries,
    displayList,
    unifiedList,
    // Actions
    fetchAll,
    fetchPending,
    create,
    update,
    deleteEntry,
    approveEntry,
    rejectEntry,
    getEntryById,
    setSearchQuery,
    // Smart Merge methods (for socket updates)
    smartMergeEntry,
    removeEntry,
    // Socket event handlers
    bindSocketEvents,
    unbindSocketEvents,
  };
});
