import { env } from '../config/env.js';
import {
  getGenerationByUuidForUser,
  getGenerationSteps,
  updateGenerationResult,
  getGenerationMetaByUuid,
} from '../repositories/scenario.repository.js';

/**
 * Валидация формата результата от n8n
 * 
 * Ожидаемый формат body (массив файлов):
 * {
 *   files: [
 *     {
 *       contentType: 'image' | 'video',
 *       url: string,  // ссылка на файл (GET запрос)
 *       thumbnailUrl?: string,
 *       duration?: number,
 *       width?: number,
 *       height?: number,
 *       size?: number,
 *       format?: string
 *     }
 *   ]
 * }
 */
function validateResultBody(body) {
  const errors = [];

  if (!body || typeof body !== 'object') {
    errors.push('Body must be an object');
    return { valid: false, errors };
  }

  // files: обязательный массив
  if (!body.files) {
    errors.push('files is required');
  } else if (!Array.isArray(body.files)) {
    errors.push('files must be an array');
  } else if (body.files.length === 0) {
    errors.push('files array cannot be empty');
  } else {
    // Валидация каждого файла
    body.files.forEach((file, index) => {
      const prefix = `files[${index}]`;
      
      // contentType
      if (!file.contentType) {
        errors.push(`${prefix}.contentType is required`);
      } else if (!['image', 'video'].includes(file.contentType)) {
        errors.push(`${prefix}.contentType must be 'image' or 'video'`);
      }

      // url: обязателен
      if (!file.url) {
        errors.push(`${prefix}.url is required`);
      } else if (typeof file.url !== 'string' || file.url.trim() === '') {
        errors.push(`${prefix}.url must be a non-empty string`);
      } else {
        try {
          new URL(file.url);
        } catch {
          errors.push(`${prefix}.url must be a valid URL`);
        }
      }

      // thumbnailUrl: опционален
      if (file.thumbnailUrl !== undefined && file.thumbnailUrl !== null) {
        if (typeof file.thumbnailUrl !== 'string') {
          errors.push(`${prefix}.thumbnailUrl must be a string`);
        } else {
          try {
            new URL(file.thumbnailUrl);
          } catch {
            errors.push(`${prefix}.thumbnailUrl must be a valid URL`);
          }
        }
      }

      // duration: опционален, только для видео
      if (file.duration !== undefined && file.duration !== null) {
        if (typeof file.duration !== 'number') {
          errors.push(`${prefix}.duration must be a number`);
        } else if (file.duration < 0) {
          errors.push(`${prefix}.duration must be >= 0`);
        }
      }

      // width/height: опциональны
      if (file.width !== undefined && file.width !== null) {
        if (!Number.isInteger(file.width) || file.width <= 0) {
          errors.push(`${prefix}.width must be a positive integer`);
        }
      }

      if (file.height !== undefined && file.height !== null) {
        if (!Number.isInteger(file.height) || file.height <= 0) {
          errors.push(`${prefix}.height must be a positive integer`);
        }
      }

      // size: опционален
      if (file.size !== undefined && file.size !== null) {
        if (typeof file.size !== 'number' || file.size < 0) {
          errors.push(`${prefix}.size must be a non-negative number`);
        }
      }

      // format: опционален
      if (file.format !== undefined && file.format !== null) {
        if (typeof file.format !== 'string' || file.format.trim() === '') {
          errors.push(`${prefix}.format must be a non-empty string`);
        }
      }
    });
  }

  return {
    valid: errors.length === 0,
    errors,
  };
}

/**
 * Получить результат генерации для пользователя
 * Формат ответа для фронта:
 * {
 *   generationUuid: string,
 *   scenarioId: string,
 *   scenarioName: string,
 *   status: 'running' | 'completed' | 'failed' | 'waiting_for_input',
 *   files: Array<{
 *     id: string,
 *     contentType: 'image' | 'video',
 *     url: string,
 *     thumbnailUrl?: string,
 *     duration?: number,
 *     width?: number,
 *     height?: number,
 *     size?: number,
 *     format?: string
 *   }>,
 *   steps: [...],
 *   startedAt: date,
 *   finishedAt: date
 * }
 */
export async function getResultForUser({ userId, generationUuid }) {
  const generation = await getGenerationByUuidForUser(generationUuid, userId);

  if (!generation) {
    return null;
  }

  const steps = await getGenerationSteps(generationUuid);

  // Преобразуем result_payload в формат для фронта
  const files = parseResultPayload(generation.result_payload);

  return {
    generationUuid: generation.generation_uuid,
    scenarioId: generation.scenario_id,
    scenarioName: generation.scenario_name,
    status: generation.status,
    files,
    steps,
    startedAt: generation.started_at,
    finishedAt: generation.finished_at,
    requestPayload: generation.request_payload,
  };
}

/**
 * Сохранить результат в БД
 */
export async function saveResultToDB(generationUuid, files) {
  const resultPayload = { files };
  return updateGenerationResult(generationUuid, resultPayload, 'completed');
}

/**
 * Получить метаданные генерации (только scenarioId и scenarioName)
 */
export async function getGenerationMeta({ userId, generationUuid }) {
  const generation = await getGenerationMetaByUuid(generationUuid, userId);

  if (!generation) {
    return null;
  }

  return {
    scenarioId: generation.scenario_id,
    scenarioName: generation.scenario_name,
  };
}

/**
 * Парсит result_payload в массив файлов
 */
function parseResultPayload(resultPayload) {
  if (!resultPayload || !resultPayload.files) {
    return [];
  }

  return resultPayload.files.map((file, index) => ({
    id: `file-${index}`,
    contentType: file.contentType,
    url: file.url,
    thumbnailUrl: file.thumbnailUrl,
    duration: file.duration,
    width: file.width,
    height: file.height,
    size: file.size,
    format: file.format,
  }));
}

/**
 * Обработать результат от n8n
 */
export async function processResultFromN8n({ generationUuid, userId, scenarioId, resultBody }) {
  // Проверяем, что generation существует и принадлежит пользователю
  const generation = await getGenerationByUuidForUser(generationUuid, userId);

  if (!generation) {
    const error = new Error(`Generation '${generationUuid}' not found or does not belong to user '${userId}'`);
    error.code = 'GENERATION_NOT_FOUND';
    error.status = 404;
    throw error;
  }

  // Валидация результата
  const validation = validateResultBody(resultBody);
  if (!validation.valid) {
    const error = new Error(`Invalid result format: ${validation.errors.join(', ')}`);
    error.code = 'INVALID_RESULT_FORMAT';
    error.status = 400;
    error.details = validation.errors;
    throw error;
  }

  // Сохраняем результат в БД
  const updatedGeneration = await updateGenerationResult(generationUuid, resultBody, 'completed');

  return {
    generationUuid: updatedGeneration.generation_uuid,
    status: updatedGeneration.status,
    files: parseResultPayload(updatedGeneration.result_payload),
  };
}

/**
 * Вызов n8n webhook для получения результата
 * stepData - данные из response_payload шага (taskId, recordId и т.д.)
 */
export async function fetchResultFromN8n({ generationUuid, userId, scenarioId, stepData = {} }) {
  // Вызываем webhook без generationUuid в пути (передаём в meta/body)
  const n8nUrl = `${env.N8N_BASE_URL}/webhook/result`;

  const payload = {
    meta: {
      generationUuid,
      userId,
      scenarioId,
      stepData,
    },
    body: stepData,
  };

  console.log('[fetchResultFromN8n] Calling:', n8nUrl);
  console.log('[fetchResultFromN8n] Payload:', JSON.stringify(payload, null, 2));

  try {
    const response = await fetch(n8nUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(payload),
    });

    console.log('[fetchResultFromN8n] Response status:', response.status, response.statusText);

    const responseText = await response.text();
    console.log('[fetchResultFromN8n] Response body:', responseText);

    if (!response.ok) {
      const error = new Error(`n8n webhook failed: ${response.status} ${response.statusText}`);
      error.code = 'N8N_WEBHOOK_ERROR';
      error.status = response.status;
      error.n8nResponse = responseText;
      throw error;
    }

    const data = JSON.parse(responseText);
    console.log('[fetchResultFromN8n] Parsed data:', data);
    return data;
  } catch (err) {
    console.error('[fetchResultFromN8n] Error:', err.message);
    if (err.code === 'N8N_WEBHOOK_ERROR') {
      throw err;
    }
    const error = new Error(`Failed to call n8n webhook: ${err.message}`);
    error.code = 'N8N_CONNECTION_ERROR';
    error.status = 503;
    throw error;
  }
}
