/* eslint-disable  @typescript-eslint/no-explicit-any */
import * as fs from 'fs';
import * as path from 'path';

import { getShowcaseState } from './preview';

/**
 * Renders a server.js module by directly calling the SSR server.
 * Returns HTML directly from the SSR server.
 */
export async function renderServerModule(
  modulePath: string,
  context?: unknown,
  data?: unknown,
): Promise<string> {
  try {
    // Get SSR server port from environment variable
    const ssrPort = process.env.PREVIEW_SSR_PORT || 3001;
    const ssrUrl = `http://localhost:${ssrPort}/load-server-module`;

    const response = await fetch(ssrUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ modulePath, context, data }),
    });

    if (!response.ok) {
      throw new Error(`Failed to render server module: ${response.statusText}`);
    }

    const result = await response.json() as { html: string };
    return result.html;
  } catch (error) {
    console.error('Error rendering server module via SSR server:', error);
    throw error;
  }
}

/**
 * Adds cache-bust parameter to URL.
 */
function addCacheBust(url: string): string {
  const separator = url.includes('?') ? '&' : '?';
  return `${url}${separator}t=${Date.now()}`;
}

/**
 * Loads a module with proper SSR setup for server.js files.
 * For other modules, uses dynamic import with cache-bust.
 * Note: server.js modules are NOT loaded here - they are rendered via renderServerModule
 */
export async function loadModule(modulePath: string): Promise<unknown> {
  return import(/* @vite-ignore */ addCacheBust(modulePath));
}

/**
 * Fetches tiles from the provided URL using bearer token from parameter
 * @param authToken - Bearer token from request header (e.g., "Bearer xxx")
 * @param tilesUrl - The original tiles URL from the Chrome extension
 * @returns The tiles response object or null if failed
 */
export async function fetchTiles(authToken?: string, tilesUrl?: string): Promise<any> {
  try {
    if (!tilesUrl) {
      console.error('No tiles URL provided');
      return null;
    }

    const headers: Record<string, string> = {};

    if (authToken) {
      headers['Authorization'] = authToken;
    }

    const response = await fetch(tilesUrl, {
      method: 'GET',
      headers,
    });

    if (!response.ok) {
      console.error('Failed to fetch tiles:', response.status, response.statusText);
      return null;
    }

    return await response.json();
  } catch (error) {
    console.error('Error fetching tiles:', error);
    return null;
  }
}

/**
 * Updates the matching section in tiles with new content and design
 * @param tilesResponse - The tiles response object
 * @param sectionName - The section name to match (e.g., 'example-section')
 * @param showcaseId - The showcase ID to match
 * @param content - The new content to replace
 * @param design - The new design to replace
 * @returns The updated tiles response object
 */
export function updateTilesSection(
  tilesResponse: any,
  sectionName: string,
  showcaseId: string,
  content: any,
  design: any,
): any {
  const targetPattern = `_${sectionName}_${showcaseId}`;

  const targetItem = tilesResponse.tiles.find((item: any) => {
    const itemId = item.sourceId;
    if (itemId && typeof itemId === 'string') {
      return itemId.includes(targetPattern);
    }
    return false;
  });

  if (targetItem) {
    // Replace only content and design, preserve all other properties including tils
    targetItem.content = content;
    targetItem.design = design;
  }

  return tilesResponse;
}

/**
 * Fetches tiles and returns all IDs of sections matching the pattern
 * @param sectionName - The section name to match (e.g., 'example-section')
 * @param showcaseId - The showcase ID to match
 * @param authToken - Bearer token from request header (e.g., "Bearer xxx")
 * @param tilesUrl - The original tiles URL from the Chrome extension
 * @returns Array of section IDs or null if not found
 */
export async function getSectionIds(sectionName: string, showcaseId: string, authToken?: string, tilesUrl?: string): Promise<string[] | null> {
  try {
    const tilesResponse = await fetchTiles(authToken, tilesUrl);
    if (!tilesResponse || !tilesResponse.tiles) {
      return null;
    }

    const targetPattern = `_${sectionName}_${showcaseId}`;

    const targetItems = tilesResponse.tiles.filter((item: any) => {
      const itemId = item.sourceId;
      return itemId?.includes(targetPattern);
    });

    return targetItems.length > 0 ? targetItems.map((item: any) => item.id) : null;
  } catch (error) {
    console.error('Error getting section IDs:', error);
    return null;
  }
}

/**
 * Gets all showcase IDs for a given section
 * @param sectionName - The section name (e.g., 'example-section')
 * @param distPath - The dist path
 * @returns Array of showcase IDs
 */
export function getShowcaseIds(sectionName: string, distPath: string): string[] {
  try {
    const showcasesPath = path.join(distPath, 'sections', sectionName, 'js', 'showcases');

    if (!fs.existsSync(showcasesPath)) {
      console.error(`Showcases directory not found for section: ${sectionName}`);
      return [];
    }

    const showcaseIds = fs.readdirSync(showcasesPath)
      .filter((file: string) => file.endsWith('.mjs') && file !== 'translations.mjs')
      .map((file: string) => file.replace('.mjs', ''));

    return showcaseIds;
  } catch (error) {
    console.error(`Error getting showcase IDs for section ${sectionName}:`, error);
    return [];
  }
}

/**
 * Updates all matching section showcases in custom content
 * @param sectionName - The section name
 * @param showcaseId - The showcase ID
 * @param distPath - The dist path
 * @param customContentSections - The sections array from custom content
 * @param authToken - Bearer token
 * @param tilesUrl - The tiles URL
 * @returns True if at least one section was updated successfully, false otherwise
 */
async function updateSectionShowcase(
  sectionName: string,
  showcaseId: string,
  distPath: string,
  customContentSections: Array<Record<string, unknown>>,
  authToken?: string,
  tilesUrl?: string,
): Promise<boolean> {
  try {
    // Get all section IDs from tiles
    const sectionIds = await getSectionIds(sectionName, showcaseId, authToken, tilesUrl);

    if (!sectionIds || sectionIds.length === 0) {
      return false;
    }

    // Process each section ID
    for (const sectionId of sectionIds) {
      // Find the section by ID in custom content
      const targetSection = customContentSections.find((section) => {
        const state = section.state as Record<string, unknown>;
        const data = state.data as Record<string, unknown>;
        return data.tileId === sectionId;
      });

      if (!targetSection) {
        console.error(`Section not found in custom content with ID: ${sectionId}`);
        continue;
      }

      // Fetch content, design, and html using getShowcaseState
      const state = targetSection.state as Record<string, unknown>;
      // eslint-disable-next-line no-await-in-loop
      const { content, design, html } = await getShowcaseState(
        sectionName,
        showcaseId,
        distPath,
        state.context as Record<string, unknown>,
      );

      // Update content, design, and html
      const data = state.data as Record<string, unknown>;
      data.content = JSON.stringify(content);
      data.design = JSON.stringify(design);
      targetSection.html = html;
    }

    return true;
  } catch (error) {
    console.error(`Error updating ${sectionName} showcase ${showcaseId}:`, error);
    return false;
  }
}

/**
 * Fetches custom content and updates all specified sections with their showcases
 * @param sectionNames - Array of section names to update (e.g., ['example-section', 'test-section'])
 * @param distPath - The dist path for getContentAndDesign
 * @param authToken - Bearer token from request header (e.g., "Bearer xxx")
 * @param customContentUrl - The custom content URL
 * @param tilesUrl - The tiles URL to fetch section IDs
 * @returns The updated custom content response or null if failed
 */
export async function updateCustomContent(
  sectionNames: string[],
  distPath: string,
  authToken?: string,
  customContentUrl?: string,
  tilesUrl?: string,
): Promise<any> {
  try {
    if (!customContentUrl || !tilesUrl) {
      console.error('No custom content or tile URL provided');
      return null;
    }

    // Fetch custom content
    const headers: Record<string, string> = {};

    if (authToken) {
      headers['Authorization'] = authToken;
    }

    const response = await fetch(customContentUrl, {
      method: 'GET',
      headers,
    });

    if (!response.ok) {
      console.error('Failed to fetch custom content:', response.status, response.statusText);
      return null;
    }

    const customContentResponse = await response.json() as Record<string, unknown>;

    const customContent = customContentResponse.customContent as Record<string, unknown>;
    if (!customContent || !customContent.sections) {
      console.error('Invalid custom content response structure');
      return null;
    }

    const customContentSections = customContent.sections as Array<Record<string, unknown>>;

    // Process all sections and showcases in parallel
    const updatePromises = sectionNames.flatMap((sectionName) => {
      const showcaseIds = getShowcaseIds(sectionName, distPath);

      return showcaseIds.map(showcaseId =>
        updateSectionShowcase(
          sectionName,
          showcaseId,
          distPath,
          customContentSections,
          authToken,
          tilesUrl,
        ),
      );
    });

    await Promise.all(updatePromises);
    return customContentResponse;
  } catch (error) {
    console.error('Error updating custom content:', error);
    return null;
  }
}
