const http = require('node:http');
const https = require('node:https');
const { URL } = require('node:url');
const { assetCategoryManager } = require('../../datasets/assetData');

function toNumber(value, fallback = 1) {
  const result = Number(value);
  return Number.isFinite(result) && result > 0 ? result : fallback;
}

function toArray(value = []) {
  if (Array.isArray(value)) {
    return value.filter((item) => typeof item !== 'undefined' && item !== null);
  }
  if (typeof value === 'string' && value.trim()) {
    return [value.trim()];
  }
  if (typeof value === 'number') {
    return [value];
  }
  return [];
}

function findModelMetadata(selection = {}) {
  if (!selection) {
    return null;
  }

  const categoryKey = selection.softwareType || 'measurement';
  if (!assetCategoryManager.hasCategory(categoryKey)) {
    return null;
  }

  const suppliers = assetCategoryManager.getCategory(categoryKey).suppliers || [];
  const supplierMatch = (entry, value) => {
    if (!entry || !value) return false;
    const key = value.toString().toLowerCase();
    return (
      (entry.id && entry.id.toLowerCase() === key) ||
      (entry.name && entry.name.toLowerCase() === key)
    );
  };

  const supplier = suppliers.find((item) => supplierMatch(item, selection.supplier));
  const types = supplier?.types || [];
  const type = types.find((item) => supplierMatch(item, selection.assetType));
  const models = type?.models || [];
  const model = models.find((item) => supplierMatch(item, selection.model));

  return model || null;
}

function buildAssetPayload({ assetSelection = {}, registrationDefaults = {} }) {
  const defaults = {
    profileId: 1,
    locationId: 1,
    processId: 1,
    status: 'actief',
    childAssets: [],
    ...registrationDefaults
  };

  const metadata = assetSelection.modelMetadata || findModelMetadata(assetSelection) || {};
  const rawName = assetSelection.assetName || assetSelection.name || assetSelection.assetType || assetSelection.model;
  const assetName = (rawName || 'Measurement asset').toString();
  const assetDescription = (assetSelection.assetDescription || assetSelection.description || assetName).toString();

  const modelId = metadata.product_model_id ?? metadata.id ?? assetSelection.modelId ?? assetSelection.model ?? null;

  const payload = {
    profile_id: toNumber(defaults.profileId, 1),
    location_id: toNumber(defaults.locationId, 1),
    process_id: toNumber(defaults.processId, 1),
    asset_name: assetName,
    asset_description: assetDescription,
    asset_status: (assetSelection.assetStatus || defaults.status || 'actief').toString(),
    product_model_id: modelId,
    product_model_uuid: metadata.product_model_uuid || metadata.uuid || null,
    child_assets: toArray(defaults.childAssets)
  };

  const validation = [];
  const missing = [];
  const tooLong = [];
  const invalid = [];

  if (!payload.asset_name) {
    missing.push('asset_name');
  } else if (payload.asset_name.length > 100) {
    tooLong.push('asset_name');
  }

  if (!payload.asset_status) {
    missing.push('asset_status');
  } else if (payload.asset_status.length > 20) {
    tooLong.push('asset_status');
  }

  if (!Number.isInteger(payload.location_id)) {
    invalid.push('location_id');
  }
  if (!Number.isInteger(payload.process_id)) {
    invalid.push('process_id');
  }
  if (!Number.isInteger(payload.profile_id)) {
    invalid.push('profile_id');
  }

  if (!Number.isInteger(payload.product_model_id)) {
    invalid.push('product_model_id');
  }

  if (!Array.isArray(payload.child_assets)) {
    invalid.push('child_assets');
  }

  if (missing.length) {
    validation.push(`missing: ${missing.join(', ')}`);
  }
  if (tooLong.length) {
    validation.push(`too long: ${tooLong.join(', ')}`);
  }
  if (invalid.length) {
    validation.push(`invalid type: ${invalid.join(', ')}`);
  }

  if (validation.length) {
    console.warn('[assetUtils] payload validation', validation.join(' | '));
  } else {
    console.info('[assetUtils] payload validation ok');
  }

  const tagNumber = typeof assetSelection.tagNumber === 'string' && assetSelection.tagNumber.trim()
    ? assetSelection.tagNumber.trim()
    : null;

  return {
    payload,
    tagNumber,
    isUpdate: Boolean(tagNumber)
  };
}

function normalizeHeaders(headers = {}, body = '') {
  const normalized = { ...headers };
  if (!Object.prototype.hasOwnProperty.call(normalized, 'Content-Length')) {
    normalized['Content-Length'] = Buffer.byteLength(body);
  }
  return normalized;
}

function prepareUrl(baseUrl = '', path = '') {
  const trimmedBase = (baseUrl || '').replace(/\/+$/g, '').replace(/\\/g, '/');
  const trimmedPath = path.startsWith('/') ? path : `/${path}`;
  if (!trimmedBase) {
    return trimmedPath;
  }
  return `${trimmedBase}${trimmedPath}`;
}

function sendHttpRequest(url, method, headers = {}, body = '') {
  const parsedUrl = new URL(url, 'http://localhost');
  const agent = parsedUrl.protocol === 'https:' ? https : http;
  const requestOptions = {
    method,
    hostname: parsedUrl.hostname,
    port: parsedUrl.port || (parsedUrl.protocol === 'https:' ? 443 : 80),
    path: `${parsedUrl.pathname}${parsedUrl.search}`,
    headers: normalizeHeaders(headers, body)
  };

  return new Promise((resolve, reject) => {
    const req = agent.request(requestOptions, (res) => {
      let raw = '';
      res.setEncoding('utf8');
      res.on('data', (chunk) => { raw += chunk; });
      res.on('end', () => resolve({ status: res.statusCode, body: raw }));
    });

    req.on('error', reject);
    if (body) {
      req.write(body);
    }
    req.end();
  });
}

function parseApiResponse(raw, status) {
  try {
    const parsed = JSON.parse(raw);
    return {
      success: parsed.success === true,
      data: parsed.data || null,
      message: parsed.message || (status >= 400 ? `HTTP ${status}` : 'Result returned')
    };
  } catch (error) {
    return {
      success: false,
      data: raw,
      message: `Unable to decode asset API response: ${error.message}`
    };
  }
}

async function syncAsset({ assetSelection = {}, registrationDefaults = {}, apiConfig = {}, nodeContext = {} }) {
  const { payload, tagNumber, isUpdate } = buildAssetPayload({ assetSelection, registrationDefaults });
  if (!apiConfig || !apiConfig.baseUrl) {
    const message = 'Asset API configuration is missing';
    console.warn('[assetUtils] ' + message, { nodeContext });
    return { success: false, data: null, message };
  }

  const path = isUpdate && tagNumber && typeof apiConfig.updatePath === 'function'
    ? apiConfig.updatePath(tagNumber)
    : apiConfig.registerPath;
  const url = prepareUrl(apiConfig.baseUrl, path);
  const method = isUpdate ? (apiConfig.updateMethod || 'PUT') : 'POST';
  const headers = apiConfig.headers || {};

  console.info('[assetUtils] Sending asset update', { nodeContext, method, url });

  try {
    const response = await sendHttpRequest(url, method, headers, JSON.stringify(payload));
    const parsed = parseApiResponse(response.body, response.status);
    return {
      success: parsed.success,
      data: parsed.data,
      message: parsed.message
    };
  } catch (error) {
    console.error('[assetUtils] Asset API request failed', error, { nodeContext });
    return {
      success: false,
      data: null,
      message: `Asset API request error: ${error.message}`
    };
  }
}

module.exports = {
  syncAsset,
  buildAssetPayload,
  findModelMetadata
};