import {
  query,
  orderBy,
  getDoc,
  getDocs,
  limit,
  doc,
  where,
} from 'firebase/firestore';
import { ROLE_THRESHOLD } from '@/data/config';
import { fetchBoardsFromFunction } from '@/utils/api/fetchBoardsFromFunction';
import { collection } from 'firebase/firestore';

//types import
import type { Ref } from 'vue';

import type {
  BoardItem,
  OrderByDirection,
  FileItem,
  UploadFileData,
  BoardAccessMode,
} from '@/types';
import type { UpdateDisplayedItemsFn, ThumbnailData } from '@/types/vueRefs';

import type {
  CollectionReference,
  DocumentData,
  Query,
  QueryConstraint,
} from 'firebase/firestore';
import type { Router } from 'vue-router';
//Board Actions

export const syncBoardAndUploadsData = <T extends BoardItem>(
  newBoard: T,
  boardsData: Ref<T>,
  uploadsData: {
    thumbnail: ThumbnailData;
    files: UploadFileData[];
  },
  createEmptyUploadFileData: () => UploadFileData,
  resetFileSlots: (files: UploadFileData[]) => void
) => {
  console.log('[syncBoardAndUploadsData] Syncing board and upload data:', {
    newBoard,
    boardsData: boardsData.value,
    uploadsData: {
      thumbnail: uploadsData.thumbnail,
      files: uploadsData.files,
    },
  });
  // 1. Sync boardsData (safe fallback)
  boardsData.value = {
    ...boardsData.value,
    docId: newBoard.docId || '',
    userId: newBoard.userId || '',
    title: newBoard.title || '',
    boardState: newBoard.boardState || { state: 'pending' },
    description: newBoard.description || '',
    announcement: newBoard.announcement || false,
    ishidden: newBoard.ishidden || false,
    boards_number: newBoard.boards_number || 0,
    created: newBoard.created || '',
    thumbnail: {
      name: newBoard.thumbnail?.name || '',
      url: newBoard.thumbnail?.url || '',
    },
    files: newBoard.files ? [...newBoard.files] : [],
  } as T;

  // --- 2) now auto-copy all extra keys from newBoard into boardsData.value ---
  const baseKeys = new Set<keyof BoardItem>([
    'docId',
    'userId',
    'title',
    'created',
    'boardState',
    'description',
    'announcement',
    'files',
    'boards_number',
    'ishidden',
    'thumbnail',
    'thumbnailUuids',
    'ckAssetUuids',
  ]);

  for (const key of Object.keys(newBoard) as Array<keyof T>) {
    if (!baseKeys.has(key as keyof BoardItem)) {
      // @ts-ignore: we know boardsData.value can hold these extra props
      boardsData.value[key] = newBoard[key];
    }
  }

  // 2. Sync thumbnail preview (old preview display only)
  if (uploadsData.thumbnail.preview && uploadsData.thumbnail.oldPreviewState) {
    uploadsData.thumbnail.preview.value = '';
    uploadsData.thumbnail.oldPreviewState.value = !!newBoard.thumbnail?.url;
    uploadsData.thumbnail.displayedName.value = newBoard.thumbnail?.name || '';
    uploadsData.thumbnail.uploadState.value = false;
    uploadsData.thumbnail.deleteTrigger.value = false;
  }

  // 3. Sync file slots
  resetFileSlots(uploadsData.files);
  if (newBoard.files?.length) {
    newBoard.files.forEach((fileItem: FileItem) => {
      const fileSlot = createEmptyUploadFileData();
      fileSlot.input = null;
      fileSlot.preview = fileItem.url;
      fileSlot.displayedName = fileItem.name;
      fileSlot.uploadState = false;
      fileSlot.deleteTrigger = false;
      fileSlot.oldPreviewState = true;
      fileSlot.previewState = true;

      uploadsData.files.push(fileSlot);
      console.log('[push check] fileSlot.input before push:', fileSlot.input);
    });
  }
  console.log('[syncBoardAndUploadsData] Synced board + upload state:', {
    thumbnail: uploadsData.thumbnail.displayedName.value,
    fileCount: uploadsData.files.length,
  });
};

export const loadBoardDetails = async (
  docIdValue: string,
  board: Ref<BoardItem>,
  currentCollection: CollectionReference,
  router: Router,
  currentboard: string,
  userRole: Ref<number>
): Promise<void> => {
  try {
    const docSnapshot = await getDoc(doc(currentCollection, docIdValue));

    if (!docSnapshot.exists()) {
      router.push({ name: `${currentboard}list` });
    } else {
      const data = docSnapshot.data();
      board.value = {
        ...(data as BoardItem),
        docId: docSnapshot.id,
      };

      if (board.value.ishidden && userRole.value < 5) {
        router.push({ name: `${currentboard}list` });
      }
    }
  } catch (error) {
    console.error('Error loading board details:', error);
  }
};
//Needs modificationm not currently used.
export const fetchUserBoards = async (
  currentCollection: CollectionReference,
  sortingOrder: Ref<OrderByDirection>,
  userRole: Ref<number>,
  currentItems: Ref<BoardItem[]>,
  updateDisplayedItems: UpdateDisplayedItemsFn,
  displayedItems: Ref<BoardItem[]>,
  currentPage: Ref<number>,
  itemsPerPage: number
) => {
  try {
    const q = query(
      currentCollection,
      orderBy('created', sortingOrder.value),
      limit(200)
    );
    const snapshot = await getDocs(q);
    const docs = snapshot.docs.map(
      (doc) =>
        ({
          docId: doc.id,
          ...doc.data(),
        } as BoardItem)
    );
    const filteredDocs = docs.filter((doc) => {
      if (doc.announcement) {
        return userRole.value >= 5 || !doc.ishidden;
      }
      return true;
    });
    currentItems.value = filteredDocs;
    updateDisplayedItems(
      currentItems,
      displayedItems,
      currentPage,
      itemsPerPage
    );
  } catch (error) {
    console.error('Error fetching Boards:', error);
    throw error;
  }
};

export async function fetchBoards<T extends BoardItem>(
  currentCollection: string,
  sortingOrder: Ref<OrderByDirection>,
  userRole: Ref<number>, // currently unused but can drive access logic
  currentItems: Ref<T[]>,
  currentPage: Ref<number>,
  itemsPerPage: number,
  access: BoardAccessMode = 'public'
): Promise<void> {
  try {
    // Fetch typed boards from cloud function
    const boards = await fetchBoardsFromFunction<T>(currentCollection, {
      sortOrder: sortingOrder.value,
      pageNumber: currentPage.value,
      itemsPerPage,
      access,
    });

    // Replace the ref value
    currentItems.value = boards.items;
  } catch (error) {
    console.error('Error fetching boards from cloud function:', error);
    throw error;
  }
}

export async function fetchElements<T extends BoardItem>(
  collection: CollectionReference<DocumentData>,
  options?: {
    sortField?: string;
    sortOrder?: 'asc' | 'desc';
    limitCount?: number;
    userId?: string;
  }
): Promise<T[]> {
  const {
    sortField = 'created',
    sortOrder = 'desc',
    limitCount = 200,
    userId,
  } = options || {};

  const q = buildBoardQuerySimple(collection, {
    sortField,
    sortOrder,
    limitCount,
    userId,
  });

  const snapshot = await getDocs(q);

  return snapshot.docs.map((doc) => {
    const data = doc.data() as Record<string, any>;
    return { ...data, docId: doc.id } as T;
  });
}

//helper for fetchBoards, fetch Elemetns
interface BuildQueryOptions {
  sortField?: string;
  sortOrder?: 'asc' | 'desc';
  limitCount?: number;
  userId?: string;
}
export function buildBoardQuerySimple(
  collection: CollectionReference,
  options: BuildQueryOptions = {}
): Query {
  const {
    sortField = 'created',
    sortOrder = 'desc',
    limitCount = 200,
    userId,
  } = options;

  const constraints = [];

  if (userId) {
    constraints.push(where('userId', '==', userId));
  }

  constraints.push(orderBy(sortField, sortOrder), limit(limitCount));

  return query(collection, ...constraints);
}

export function buildBoardQuery(
  collection: CollectionReference,
  userRole: Ref<number>,
  userId: Ref<string>,
  sortingOrder: Ref<OrderByDirection>,
  limitCount: number = 200
): Query {
  if (userRole.value >= ROLE_THRESHOLD.ADMIN) {
    // Admin can see all
    return query(
      collection,
      orderBy('announcement', 'desc'),
      orderBy('created', sortingOrder.value),
      limit(limitCount)
    );
  } else {
    // Regular user: only their documents
    return query(
      collection,
      where('userId', '==', userId.value),
      orderBy('announcement', 'desc'),
      orderBy('created', sortingOrder.value),
      limit(limitCount)
    );
  }
}

const userNameCache = new Map<string, string>();

export async function fetchUserDisplayName(userId: string): Promise<string> {
  const { $firebase } = useNuxtApp();
  const usersCollection = $firebase.usersCollection;
  if (userNameCache.has(userId)) {
    return userNameCache.get(userId)!;
  }

  try {
    const userDoc = await getDoc(doc(usersCollection, userId));
    if (userDoc.exists()) {
      const userData = userDoc.data();
      const displayName = userData.name || userId;
      userNameCache.set(userId, displayName);
      return displayName;
    }
    userNameCache.set(userId, userId);
    return userId;
  } catch (error) {
    console.error('Error fetching user display name:', error);
    userNameCache.set(userId, userId);
    return userId;
  }
}
