/**
 * Service für HTTP-Aufrufe an click-TT/HTTV-Seiten mit Logging.
 * Dient zum Verständnis der Seiten-Struktur und URL-Varianten je nach Verband/Saison.
 *
 * URL-Struktur httv.click-tt.de (und andere Verbände):
 * - leaguePage: /cgi-bin/WebObjects/nuLigaTTDE.woa/wa/leaguePage?championship=HTTV+25%2F26
 * - regionMeetingFilter: /cgi-bin/WebObjects/nuLigaTTDE.woa/wa/regionMeetingFilter?championship=HTTV+25%2F26
 * - clubInfoDisplay: /cgi-bin/WebObjects/nuLigaTTDE.woa/wa/clubInfoDisplay?club=1060
 */

import fetch from 'node-fetch';
import HttpPageFetchLog from '../models/HttpPageFetchLog.js';
import { devLog } from '../utils/logger.js';

/** Verband → click-TT Subdomain */
const ASSOCIATION_TO_DOMAIN = {
  HeTTV: 'httv.click-tt.de',
  HTTV: 'httv.click-tt.de',
  RTTV: 'rttv.click-tt.de',
  WTTV: 'wttv.click-tt.de',
  TTVNw: 'ttvnw.click-tt.de',
  BTTV: 'battv.click-tt.de',
};

const SNIPPET_MAX_LEN = 2000;

function serializeHeaders(headers) {
  if (!headers) return null;

  if (typeof headers.raw === 'function') {
    try {
      return JSON.stringify(headers.raw());
    } catch {
      // Fallback below
    }
  }

  try {
    const entries = {};
    if (typeof headers.forEach === 'function') {
      headers.forEach((value, key) => {
        entries[key] = value;
      });
    } else {
      Object.assign(entries, headers);
    }
    return JSON.stringify(entries);
  } catch {
    return null;
  }
}

/**
 * Ermittelt die click-TT-Domain für einen Verband
 */
function getDomainForAssociation(association) {
  if (!association) return null;
  const key = association.replace(/\s/g, '');
  return ASSOCIATION_TO_DOMAIN[association] ?? ASSOCIATION_TO_DOMAIN[key] ?? null;
}

/**
 * Baut die leaguePage-URL für einen Verband
 * @param {Object} opts
 * @param {string} opts.association - z.B. HeTTV, HTTV
 * @param {string} opts.championship - z.B. "HTTV 25/26" oder "K43 25/26" (Frankfurt)
 */
function buildLeaguePageUrl(opts) {
  const { association, championship } = opts;
  const domain = getDomainForAssociation(association) || 'httv.click-tt.de';
  const champEncoded = encodeURIComponent(championship || 'HTTV 25/26');
  return `https://${domain}/cgi-bin/WebObjects/nuLigaTTDE.woa/wa/leaguePage?championship=${champEncoded}`;
}

/**
 * Baut die clubInfoDisplay-URL
 */
function buildClubInfoDisplayUrl(opts) {
  const { association, clubId } = opts;
  const domain = getDomainForAssociation(association) || 'httv.click-tt.de';
  return `https://${domain}/cgi-bin/WebObjects/nuLigaTTDE.woa/wa/clubInfoDisplay?club=${encodeURIComponent(clubId)}`;
}

/**
 * Baut die regionMeetingFilter-URL
 */
function buildRegionMeetingFilterUrl(opts) {
  const { association, championship } = opts;
  const domain = getDomainForAssociation(association) || 'httv.click-tt.de';
  const champEncoded = encodeURIComponent(championship || 'HTTV 25/26');
  return `https://${domain}/cgi-bin/WebObjects/nuLigaTTDE.woa/wa/regionMeetingFilter?championship=${champEncoded}`;
}

/**
 * Extrahiert die Basis-Domain aus einer URL
 */
function extractBaseDomain(url) {
  try {
    const u = new URL(url);
    return u.hostname;
  } catch {
    return 'unknown';
  }
}

/**
 * Erstellt einen Response-Snippet (gekürzt)
 */
function createResponseSnippet(body, maxLen = SNIPPET_MAX_LEN) {
  if (!body || typeof body !== 'string') return null;
  const trimmed = body.trim();
  if (trimmed.length <= maxLen) return trimmed;
  return trimmed.substring(0, maxLen) + '\n...[gekürzt]';
}

/**
 * Führt einen HTTP-Aufruf durch und loggt das Ergebnis
 */
async function fetchWithLogging(options) {
  const {
    url,
    fetchType = 'unknown',
    association = null,
    championship = null,
    clubIdParam = null,
    userId = null,
    method = 'GET',
    body = null,
    headers: customHeaders = {},
  } = options;

  const baseDomain = extractBaseDomain(url);
  const startTime = Date.now();

  let origin;
  try { origin = new URL(url).origin + '/'; } catch { origin = 'https://httv.click-tt.de/'; }
  const headers = {
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Language': 'de,en-US;q=0.7,en;q=0.3',
    'Referer': origin,
    'Origin': origin.replace(/\/$/, ''),
    ...customHeaders,
  };

  try {
    const fetchOpts = {
      method,
      headers,
      timeout: 30000,
      redirect: method === 'POST' ? 'manual' : 'follow',
    };
    if (body && (method === 'POST' || method === 'PUT')) {
      fetchOpts.body = body;
    }
    const response = await fetch(url, fetchOpts);

    const executionTimeMs = Date.now() - startTime;
    const contentType = response.headers.get('content-type') || null;
    const responseBody = await response.text();
    const success = response.ok;
    const snippet = createResponseSnippet(responseBody);
    const requestHeaders = serializeHeaders(headers);
    const responseHeaders = serializeHeaders(response.headers);

    await HttpPageFetchLog.create({
      userId,
      fetchType,
      baseDomain,
      fullUrl: url,
      association,
      championship,
      clubIdParam,
      requestMethod: method,
      requestHeaders,
      requestBody: body,
      httpStatus: response.status,
      success,
      responseSnippet: snippet,
      contentType,
      responseHeaders,
      responseBody,
      responseUrl: response.url || url,
      errorMessage: success ? null : `HTTP ${response.status}: ${response.statusText}`,
      executionTimeMs,
    });

    devLog(`[ClickTT] ${fetchType} ${url} → ${response.status} (${executionTimeMs}ms)`);

    return {
      success,
      status: response.status,
      contentType,
      body: responseBody,
      executionTimeMs,
      headers: response.headers,
      responseUrl: response.url || url,
    };
  } catch (error) {
    const executionTimeMs = Date.now() - startTime;

    await HttpPageFetchLog.create({
      userId,
      fetchType,
      baseDomain,
      fullUrl: url,
      association,
      championship,
      clubIdParam,
      requestMethod: method,
      requestHeaders: serializeHeaders(headers),
      requestBody: body,
      httpStatus: null,
      success: false,
      responseSnippet: null,
      contentType: null,
      responseHeaders: null,
      responseBody: null,
      responseUrl: null,
      errorMessage: error.message,
      executionTimeMs,
    });

    devLog(`[ClickTT] ${fetchType} ${url} → ERROR: ${error.message}`);

    throw error;
  }
}

/**
 * Ruft die leaguePage-Seite ab (Ligenübersicht)
 */
async function fetchLeaguePage(opts) {
  const { association = 'HeTTV', championship = 'HTTV 25/26', userId } = opts;
  const url = buildLeaguePageUrl({ association, championship });
  return fetchWithLogging({
    url,
    fetchType: 'leaguePage',
    association,
    championship,
    userId,
  });
}

/**
 * Ruft die clubInfoDisplay-Seite ab (Vereinsinfo)
 */
async function fetchClubInfoDisplay(opts) {
  const { association = 'HeTTV', clubId, userId } = opts;
  const url = buildClubInfoDisplayUrl({ association, clubId });
  return fetchWithLogging({
    url,
    fetchType: 'clubInfoDisplay',
    association,
    clubIdParam: String(clubId),
    userId,
  });
}

/**
 * Ruft die regionMeetingFilter-Seite ab (Regionsspielplan)
 */
async function fetchRegionMeetingFilter(opts) {
  const { association = 'HeTTV', championship = 'HTTV 25/26', userId } = opts;
  const url = buildRegionMeetingFilterUrl({ association, championship });
  return fetchWithLogging({
    url,
    fetchType: 'regionMeetingFilter',
    association,
    championship,
    userId,
  });
}

/**
 * Ruft eine beliebige URL ab (für manuelle Tests)
 */
async function fetchArbitraryUrl(url, opts = {}) {
  const { fetchType = 'arbitrary', userId } = opts;
  return fetchWithLogging({
    url,
    fetchType,
    userId,
  });
}

export default {
  fetchLeaguePage,
  fetchClubInfoDisplay,
  fetchRegionMeetingFilter,
  fetchArbitraryUrl,
  fetchWithLogging,
  buildLeaguePageUrl,
  buildClubInfoDisplayUrl,
  buildRegionMeetingFilterUrl,
  getDomainForAssociation,
  ASSOCIATION_TO_DOMAIN,
};
