import { Platform, Alert } from 'react-native';
import * as FileSystemLegacy from 'expo-file-system/legacy';
import * as Print from 'expo-print';
import { Buffer } from 'buffer';
import { apiFetch } from './api';
import { API_URL, PACKIE_TEST_LABEL_PDF_URL } from '../constants/defaults';
import { parseOrderAddress, buildNineFieldQr, getStockLabel, compactDigits, zplSafe } from '../utils/helpers';

/**
 * Fetch sender details from the API.
 * Returns the sender object on success, or a default fallback on failure.
 * If the response is 401, calls handleSessionExpired() and returns null.
 */
export const fetchSenderDetails = async (handleSessionExpired) => {
  try {
    const res = await apiFetch(`${API_URL}?action=get_sender_details`);
    if (res.status === 401) {
      handleSessionExpired();
      return null;
    }
    const data = await res.json();
    if (data?.success && data?.sender) return data.sender;
  } catch (e) {
    console.log('fetchSenderDetails failed', e);
  }
  return {
    company: 'Afrihair Ltd',
    streetAddress: '247 Cuba Street',
    city: 'Palmerston North',
    postCode: '4410',
    country: 'NZ',
    contactName: 'Afrihair',
  };
};

export const buildLocalLabelData = async ({ order, stockId, fetchSenderDetailsFn, isTest = false, packieStocks }) => {
  const sender = await fetchSenderDetailsFn();
  if (!sender) return null;

  const parsed = parseOrderAddress(order);
  const satchelLabel = getStockLabel(stockId, packieStocks);
  const qrString = buildNineFieldQr({
    company: '',
    building: parsed.building,
    street: parsed.street,
    suburb: parsed.suburb || parsed.city,
    country: parsed.country || 'NZ',
    postcode: parsed.postcode,
    phone: order?.phone || '',
    reference: `Ref: ${order?.name || order?.id || ''}`,
    contactName: order?.customer || '',
  });

  return { order, sender, qrString, satchelLabel, isTest };
};

/**
 * Build ZPL payload for a courier shipping label.
 */
export const buildCourierLabelZpl = ({ sender, order, qrString, satchelLabel = 'DL', isTest = false }) => {
  const parsed = parseOrderAddress(order);
  const refValue = `Ref: ${order?.id || order?.name || ''}`;
  const orderNo = String(order?.name || order?.id || '').replace('#', '');
  const barcodeData = compactDigits(order?.id || order?.name || '') || '00794210392723651267';
  const receiverLine1 = zplSafe(order?.customer || (isTest ? 'Test Customer' : 'Receiver'));
  const receiverLine2 = zplSafe(parsed.building || parsed.street || (isTest ? '123 Test Street' : ''));
  const receiverLine3 = zplSafe(`${parsed.suburb || parsed.city || ''} ${parsed.postcode || ''}`.trim());
  const footerDate = new Date().toLocaleDateString('en-NZ');

  // ZPL template mirrors your label sections with clear boxed rows.
  return [
    '^XA',
    '^CI28',
    '^PW812',
    '^LL1218',
    '^LH0,0',

    // Top brand band
    '^FO0,0^GB812,205,3^FS',
    '^FO24,26^A0N,44,44^FDAFRIHAIR SHIPPING^FS',
    '^FO24,80^A0N,30,30^FDLabel Preview^FS',
    `^FO24,138^A0N,48,48^FD${zplSafe(barcodeData)}^FS`,

    // Barcode band
    '^FO0,205^GB812,150,3^FS',
    `^FO110,240^BY3,2,70^BCN,70,Y,N,N^FD${zplSafe(barcodeData)}^FS`,

    // Receiver + QR band
    '^FO0,355^GB812,390,3^FS',
    `^FO24,395^A0N,40,40^FD${receiverLine1}^FS`,
    `^FO24,448^A0N,34,34^FD${receiverLine2}^FS`,
    `^FO24,495^A0N,34,34^FD${receiverLine3}^FS`,
    `^FO24,560^A0N,44,44^FD${zplSafe(order?.phone || '')}^FS`,
    '^FO24,620^A0N,34,34^FDSpecial instruction:^FS',
    `^FO24,662^A0N,30,30^FD${zplSafe(order?.note || '')}^FS`,

    `^FO500,395^A0N,36,36^FD${zplSafe(refValue)}^FS`,
    `^FO500,435^A0N,36,36^FDOrder #: ${zplSafe(orderNo)}^FS`,
    `^FO500,485^BQN,2,6^FDLA,${zplSafe(qrString)}^FS`,

    // Sender band
    '^FO0,745^GB812,220,3^FS',
    '^FO24,785^A0N,36,36^FDSender:^FS',
    `^FO24,830^A0N,34,34^FD${zplSafe(sender.company || 'Afrihair Ltd')}^FS`,
    `^FO24,872^A0N,34,34^FD${zplSafe(sender.contactName || 'Daniel')}^FS`,
    `^FO24,914^A0N,34,34^FD${zplSafe(sender.streetAddress || '247 Cuba Street')}^FS`,
    `^FO24,956^A0N,34,34^FD${zplSafe(sender.city || 'Palmerston North')} ${zplSafe(sender.postCode || '4410')}^FS`,
    '^FO520,860^A0N,60,60^FDCourierIT^FS',

    // Footer band
    '^FO0,965^GB812,130,3^FS',
    `^FO24,1020^A0N,46,46^FDSatchel Size: ${zplSafe(satchelLabel)}^FS`,
    `^FO390,1020^A0N,46,46^FD${zplSafe(footerDate)}^FS`,
    '^FO700,1020^A0N,46,46^FD1 of 1^FS',

    '^XZ',
  ].join('\n');
};

const getConfiguredPrinterHost = settings => String(settings.printerIpAddress || settings.localPrinterHostname || '').trim();

const base64ToBytes = base64 => Buffer.from(String(base64 || ''), 'base64');

const normalizeSocketPayload = (payload, encoding = 'utf8') => {
  if (payload instanceof Uint8Array || Buffer.isBuffer(payload)) return payload;
  if (encoding === 'base64') return base64ToBytes(payload);
  return Buffer.from(String(payload || ''), encoding || 'utf8');
};

const printPayloadToBase64 = (payload, encoding = 'binary') => {
  if (encoding === 'base64' && typeof payload === 'string') return payload;
  if (payload instanceof Uint8Array || Buffer.isBuffer(payload)) return Buffer.from(payload).toString('base64');
  return Buffer.from(String(payload || ''), encoding === 'binary' ? 'binary' : 'utf8').toString('base64');
};

/**
 * Send a raw TCP payload to a network printer on the given host:port.
 */
export const sendRawSocketPrint = async (host, port, payload, encoding = 'utf8') => {
  const TcpSocketModule = require('react-native-tcp-socket');
  const TcpSocket = TcpSocketModule.default || TcpSocketModule;
  const safePort = parseInt(String(port || '9100'), 10) || 9100;
  const bytes = normalizeSocketPayload(payload, encoding);

  return new Promise((resolve, reject) => {
    let settled = false;
    let client = null;
    const timer = setTimeout(() => fail(new Error('Printer connection timed out.')), 10000);

    const cleanup = () => {
      clearTimeout(timer);
      if (client) {
        client.removeAllListeners('error');
        client.removeAllListeners('close');
      }
    };

    const fail = err => {
      if (settled) return;
      settled = true;
      cleanup();
      try { client?.destroy?.(); } catch (_) {}
      reject(err instanceof Error ? err : new Error(String(err || 'Socket error')));
    };

    client = TcpSocket.createConnection({ host, port: safePort }, () => {
      client.write(bytes, undefined, err => {
        if (err) {
          fail(err);
          return;
        }
        client.end();
        if (!settled) {
          settled = true;
          cleanup();
          resolve(true);
        }
      });
    });

    client.on('error', fail);
  });
};

export const fetchBackendPrintPayload = async ({ order, stockId, settings, payloadType = 'THERMAL', isTest = false }) => {
  const action = payloadType === 'LASER' ? 'get_laser_pdf_payload' : 'get_thermal_payload';
  const res = await apiFetch(`${API_URL}?action=${action}`, {
    method: 'POST',
    body: JSON.stringify({
      action,
      order_id: order?.id || '',
      order,
      stock_id: stockId || 'none',
      printer_type: payloadType,
      printer_driver: settings?.localPrinterDriver || 'direct',
      pdf_url: isTest ? (settings?.testLabelPdfUrl || PACKIE_TEST_LABEL_PDF_URL) : '',
      is_test: isTest ? 1 : 0,
    }),
  });

  const text = await res.text();
  let data;
  try {
    data = JSON.parse(text);
  } catch (_) {
    throw new Error(text || 'Server returned a non-JSON print payload response.');
  }

  if (!res.ok || !data?.success) {
    throw new Error(data?.error || `Could not fetch ${payloadType.toLowerCase()} print payload.`);
  }

  return {
    payload: data.payload || '',
    encoding: data.encoding || (payloadType === 'LASER' ? 'base64' : 'utf8'),
    contentType: data.content_type || '',
  };
};

export const fetchPdfUrlPayload = async (url) => {
  const safeUrl = String(url || '').trim();
  if (!safeUrl) throw new Error('No PDF label URL is configured.');

  const res = await fetch(safeUrl, {
    method: 'GET',
    headers: { Accept: 'application/pdf,*/*' },
  });
  if (!res.ok) throw new Error(`Could not download PDF label (${res.status}).`);

  const contentType = String(res.headers?.get?.('content-type') || '').toLowerCase();
  const arrayBuffer = await res.arrayBuffer();
  const payload = Buffer.from(arrayBuffer);
  if (!payload.length) throw new Error('Downloaded PDF label was empty.');
  if (contentType && !contentType.includes('pdf') && !payload.toString('utf8', 0, 5).startsWith('%PDF')) {
    throw new Error('Packie did not return a PDF label.');
  }

  return { payload, encoding: 'binary', contentType: contentType || 'application/pdf' };
};

export const fetchPackieLabelPayload = async ({ order, maxAttempts = 30, delayMs = 2000 }) => {
  const orderName = order?.name || '';
  const orderId = order?.id || '';

  for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
    try {
      const res = await apiFetch(`${API_URL}?action=get_packie_label_payload`, {
        method: 'POST',
        body: JSON.stringify({
          action: 'get_packie_label_payload',
          order_id: orderId,
          order_name: orderName,
        }),
      });

      const text = await res.text();
      let data = null;
      try {
        data = JSON.parse(text);
      } catch (_) {
        if (res.status !== 202) throw new Error(text || 'Server returned a non-JSON label response.');
      }

      if (res.ok && data?.success && data?.payload) {
        return {
          payload: data.payload,
          encoding: data.encoding || 'base64',
          contentType: data.content_type || 'application/pdf',
          pdfUrl: data.pdf_url || '',
          consignmentId: data.consignment_id || null,
        };
      }

      if (res.status !== 202 && data?.error && String(data.error).toLowerCase().includes('unknown action')) {
        throw new Error('The backend is missing the Packie label PDF endpoint. Deploy the updated backend/api.php, then try the live print again.');
      }

      if (res.status !== 202 && data?.error && attempt === maxAttempts) {
        throw new Error(data.error);
      }
    } catch (e) {
      if (attempt === maxAttempts) throw e;
    }

    await new Promise(resolve => setTimeout(resolve, delayMs));
  }

  throw new Error('Packie label was not ready yet. Try printing again in a moment.');
};

export const sendSilentPrintJob = async ({ order, stockId, settings, viewShotRef, setLabelPrintData, fetchSenderDetailsFn, isTest = false, packieStocks }) => {
  const host = getConfiguredPrinterHost(settings);
  const port = '9100';
  if (!host) {
    Alert.alert('Printer Not Set', 'Set a printer IP address or hostname first.');
    return false;
  }

  const printerType = String(settings.printerType || 'THERMAL').toUpperCase();
  try {
    if (printerType === 'LASER') {
      const { payload, encoding } = isTest
        ? await fetchPdfUrlPayload(settings?.testLabelPdfUrl || PACKIE_TEST_LABEL_PDF_URL)
        : await fetchPackieLabelPayload({ order });
      await sendRawSocketPrint(host, port, payload, encoding);
      return true;
    }

    const { payload, encoding } = await fetchBackendPrintPayload({ order, stockId, settings, payloadType: 'THERMAL', isTest });
    await sendRawSocketPrint(host, port, payload, encoding);
    return true;
  } catch (e) {
    // Keep thermal labels useful even if the server-side payload hook is unavailable.
    if (printerType === 'THERMAL') {
      try {
        const labelData = await buildLocalLabelData({ order, stockId, fetchSenderDetailsFn, isTest, packieStocks });
        if (!labelData) return false;
        const { sender, qrString, satchelLabel } = labelData;
        const payload = buildCourierLabelZpl({ sender, order, qrString, satchelLabel, isTest });
        await sendRawSocketPrint(host, port, payload, 'utf8');
        return true;
      } catch (fallbackErr) {
        Alert.alert('Direct Print Error', fallbackErr?.message || e?.message || 'Could not send print job to the printer.');
        return false;
      }
    }

    if (printerType === 'LASER' && isTest) {
      Alert.alert('Direct Print Error', e?.message || 'Could not download and send the Packie PDF test label.');
      return false;
    }

    Alert.alert('Direct Print Error', e?.message || 'Could not send print job to the printer.');
    return false;
  } finally {
    if (setLabelPrintData && viewShotRef) setLabelPrintData(null);
  }
};

/**
 * Print a shipping label via the Brother QL printer SDK (ViewShot image capture).
 *
 * @param {object}   params
 * @param {object}   params.order                - The order to print a label for
 * @param {string}   params.stockId              - Stock/satchel ID (or 'custom')
 * @param {object}   params.settings             - Master settings object (replaces masterSettings)
 * @param {object}   params.viewShotRef          - React ref to the ViewShot component
 * @param {function} params.setLabelPrintData    - State setter for label print data
 * @param {function} params.fetchSenderDetailsFn - Bound fetchSenderDetails(handleSessionExpired)
 * @param {boolean}  [params.isTest=false]       - Whether this is a test print
 * @param {Array}    params.packieStocks         - Array of packie stock objects
 */
export const printBrotherLabel = async ({ order, settings, isTest = false }) => {
  const host = getConfiguredPrinterHost(settings);
  if (!host) {
    Alert.alert('Printer Not Set', 'Enter the Brother printer IP address in Settings \u2192 Local Printer.');
    return false;
  }

  try {
    const labelType = String(settings.localPrinterLabelType || 'DK-11247').trim().toUpperCase();
    const BrothLib = require('react-native-brother-printers');
    const { NativeModules } = require('react-native');
    const BrotherPrinter = BrothLib.default || BrothLib;
    const nativeBrother = NativeModules?.ReactNativeBrotherPrinters;
    if (typeof nativeBrother?.printImage !== 'function') {
      throw new Error('Brother QL printing is not available in this Android build. The installed Brother printer module is missing its native printImage bridge.');
    }
    if (typeof nativeBrother?.printPDF !== 'function' || typeof BrotherPrinter.printPDF !== 'function') {
      throw new Error('Brother PDF printing is not available in this Android build. Rebuild the app with the updated Brother native bridge.');
    }
    const device = {
      ipAddress: host,
      modelName: 'QL-1110NWB',
      printerName: 'QL-1110NWB',
    };
    const providedPayload = order?.__packie_label_payload;
    const providedPdfUrl = order?.__packie_label_pdf_url;
    const { payload, encoding } = isTest
      ? await fetchPdfUrlPayload(settings?.testLabelPdfUrl || PACKIE_TEST_LABEL_PDF_URL)
      : providedPayload
        ? {
            payload: providedPayload,
            encoding: order?.__packie_label_encoding || 'base64',
            contentType: order?.__packie_label_content_type || 'application/pdf',
          }
        : providedPdfUrl
          ? await fetchPdfUrlPayload(providedPdfUrl)
          : await fetchPackieLabelPayload({ order });

    await BrotherPrinter.printPDF(device, printPayloadToBase64(payload, encoding), {
      labelSize: labelType,
      labelSizeName: labelType,
      autoCut: true,
    });
    return true;
  } catch (e) {
    Alert.alert('Brother Print Error', e?.message || 'Failed to send label to Brother printer.');
    return false;
  }
};

/**
 * Print a shipping label using the system print dialog (expo-print).
 *
 * @param {object}   params
 * @param {object}   params.order                - The order to print a label for
 * @param {string}   params.stockId              - Stock/satchel ID (or 'custom')
 * @param {object}   params.settings             - Master settings object (replaces masterSettings)
 * @param {object}   params.viewShotRef          - React ref to the ViewShot component
 * @param {function} params.setLabelPrintData    - State setter for label print data
 * @param {function} params.fetchSenderDetailsFn - Bound fetchSenderDetails(handleSessionExpired)
 * @param {boolean}  [params.isTest=false]       - Whether this is a test print
 * @param {Array}    params.packieStocks         - Array of packie stock objects
 */
export const printSystemLabel = async ({ order, stockId, settings, viewShotRef, setLabelPrintData, fetchSenderDetailsFn, isTest = false, packieStocks }) => {
  if (!isTest) {
    const providedPayload = order?.__packie_label_payload;
    const providedPdfUrl = order?.__packie_label_pdf_url;
    try {
      const { payload, encoding } = providedPayload
        ? {
            payload: providedPayload,
            encoding: order?.__packie_label_encoding || 'base64',
            contentType: order?.__packie_label_content_type || 'application/pdf',
          }
        : providedPdfUrl
          ? await fetchPdfUrlPayload(providedPdfUrl)
          : await fetchPackieLabelPayload({ order });
      const base64 = printPayloadToBase64(payload, encoding);
      const fileUri = `${FileSystemLegacy.cacheDirectory || ''}packie-label-${order?.id || Date.now()}.pdf`;
      await FileSystemLegacy.writeAsStringAsync(fileUri, base64, { encoding: 'base64' });
      await Print.printAsync({ uri: fileUri });
      return true;
    } catch (e) {
      Alert.alert('System Print Error', e?.message || 'Could not open the Packie PDF label.');
      return false;
    }
  }

  const sender = await fetchSenderDetailsFn();
  if (!sender) return false;

  const parsed = parseOrderAddress(order);
  const satchelLabel = getStockLabel(stockId, packieStocks);

  let qrString;
  try {
    qrString = buildNineFieldQr({
      company: '',
      building: parsed.building,
      street: parsed.street,
      suburb: parsed.suburb || parsed.city,
      country: parsed.country || 'NZ',
      postcode: parsed.postcode,
      phone: order?.phone || '',
      reference: `Ref: ${order?.name || order?.id || ''}`,
      contactName: order?.customer || '',
    });
  } catch (_e) {
    qrString = '||||||||';
  }

  // Render the ShippingLabelView off-screen and capture as PNG so the
  // system print dialog shows exactly the same layout as the Brother path.
  setLabelPrintData({ order, sender, qrString, satchelLabel, isTest });
  await new Promise(r => setTimeout(r, 700));

  try {
    if (!viewShotRef.current) throw new Error('Label renderer not ready \u2014 try again.');
    const uri = await viewShotRef.current.capture();
    // expo-file-system is always available in Expo builds; use it to base64-encode the PNG
    const fileUri = String(uri).startsWith('file://') ? uri : `file://${uri}`;
    const base64 = await FileSystemLegacy.readAsStringAsync(fileUri, { encoding: 'base64' });
    const html = `<!DOCTYPE html><html><head><meta charset="utf-8"/><style>*{margin:0;padding:0;}body{background:#fff;}img{width:100%;height:auto;display:block;}</style></head><body><img src="data:image/png;base64,${base64}"/></body></html>`;
    await Print.printAsync({ html });
    return true;
  } catch (e) {
    Alert.alert('System Print Error', e?.message || 'Could not open the system print dialog.');
    return false;
  } finally {
    setLabelPrintData(null);
  }
};

/**
 * Route a print job to the correct driver: system, brother, or ZPL/raw.
 *
 * @param {object}   params
 * @param {object}   params.order                - The order to print a label for
 * @param {string}   params.stockId              - Stock/satchel ID (or 'custom')
 * @param {object}   params.settings             - Master settings object (replaces masterSettings)
 * @param {object}   params.viewShotRef          - React ref to the ViewShot component
 * @param {function} params.setLabelPrintData    - State setter for label print data
 * @param {function} params.fetchSenderDetailsFn - Bound fetchSenderDetails(handleSessionExpired)
 * @param {boolean}  [params.isTest=false]       - Whether this is a test print
 * @param {Array}    params.packieStocks         - Array of packie stock objects
 */
export const printOrderLocally = async ({ order, stockId, settings, viewShotRef, setLabelPrintData, fetchSenderDetailsFn, isTest = false, packieStocks }) => {
  const driver = String(settings.localPrinterDriver || 'brother').toLowerCase();
  if (driver === 'system') {
    if (Platform.OS !== 'android') {
      Alert.alert('System Print', 'Use DIRECT printing on iOS to avoid the Apple print dialog.');
      return false;
    }
    return printSystemLabel({ order, stockId, settings, viewShotRef, setLabelPrintData, fetchSenderDetailsFn, isTest, packieStocks });
  }

  const host = getConfiguredPrinterHost(settings);
  if (!host) {
    Alert.alert('Printer Not Set', 'Set a local printer hostname or IP address first.');
    return false;
  }

  if (driver === 'direct') {
    return sendSilentPrintJob({ order, stockId, settings, viewShotRef, setLabelPrintData, fetchSenderDetailsFn, isTest, packieStocks });
  }

  if (Platform.OS !== 'android' && driver === 'brother') {
    Alert.alert('Brother Print', 'Brother SDK printing is only configured for Android. Use DIRECT printing for iOS.');
    return false;
  }

  // Brother QL path -- uses ViewShot image capture + react-native-brother-printers SDK
  if (driver === 'brother') {
    return printBrotherLabel({ order, stockId, settings, viewShotRef, setLabelPrintData, fetchSenderDetailsFn, isTest, packieStocks });
  }

  // -- ZPL / RAW fallback (Zebra and other TCP-9100 printers) --
  const port = String(settings.localPrinterPort || '9100').trim() || '9100';
  const sender = await fetchSenderDetailsFn();
  if (!sender) return false;

  const parsed = parseOrderAddress(order);
  const qrString = buildNineFieldQr({
    company: '',
    building: parsed.building,
    street: parsed.street,
    suburb: parsed.suburb || parsed.city,
    country: parsed.country || 'NZ',
    postcode: parsed.postcode,
    phone: order?.phone || '',
    reference: `Ref: ${order?.name || order?.id || ''}`,
    contactName: order?.customer || '',
  });

  const satchelLabel = getStockLabel(stockId, packieStocks);
  const payload = driver === 'raw'
    ? `${qrString}\n${order?.customer || ''}\n${parsed.street || ''}\n${parsed.suburb || parsed.city || ''}\n${sender.company || ''}\n${sender.streetAddress || ''}\n${sender.city || ''} ${sender.postCode || ''}\n`
    : buildCourierLabelZpl({ sender, order, qrString, satchelLabel, isTest });

  try {
    await sendRawSocketPrint(host, port, payload);
    return true;
  } catch (e) {
    Alert.alert('Local Print Error', e?.message || 'Could not send print job to local printer.');
    return false;
  }
};

/**
 * Discover network printers using mDNS/Zeroconf (Bonjour).
 * Returns an array of { name, host, port, protocol } objects.
 */
export const discoverMdnsPrinters = async () => {
  const ZeroconfModule = require('react-native-zeroconf');
  const Zeroconf = ZeroconfModule.default || ZeroconfModule;
  const zeroconf = new Zeroconf();
  const found = {};

  const addService = (service, protocolHint = 'tcp') => {
    const name = String(service?.name || service?.host || 'Printer').trim();
    // Prefer a resolved IP address over a .local hostname (Android may not resolve .local)
    const ip = service?.addresses?.[0] || '';
    const host = String(ip || service?.host || '').trim();
    const port = service?.port ? String(service.port) : '9100';
    if (!host) return;
    const key = `${name}-${host}-${port}`;
    found[key] = { name, host, port, protocol: protocolHint };
  };

  await new Promise(resolve => {
    const timeout = setTimeout(resolve, 7000);

    zeroconf.on('resolved', service => addService(service));
    zeroconf.on('found', service => addService(service));
    zeroconf.on('error', err => {
      console.log('zeroconf scan error', err);
    });

    try {
      zeroconf.scan('pdl-datastream', 'tcp', 'local.');
      zeroconf.scan('ipp', 'tcp', 'local.');
      zeroconf.scan('ipps', 'tcp', 'local.');  // AirPrint (HTTPS IPP) -- DCP/MFC printers
      zeroconf.scan('printer', 'tcp', 'local.');
    } catch (e) {
      console.log('zeroconf scan start failed', e);
    }

    setTimeout(() => {
      clearTimeout(timeout);
      resolve();
    }, 7050);
  });

  try { zeroconf.stop(); } catch (e) { console.log('zeroconf stop error', e); }
  try { zeroconf.removeAllListeners(); } catch (e) { console.log('zeroconf remove listeners error', e); }

  return Object.values(found);
};

/**
 * Scan for network printers using the appropriate method based on the configured driver.
 *
 * @param {object}   params
 * @param {object}   params.settings               - Master settings object (replaces masterSettings)
 * @param {function} params.setIsScanningPrinters   - State setter for scanning indicator
 * @param {function} params.setDiscoveredPrinters   - State setter for discovered printers list
 */
export const scanForNetworkPrinters = async ({ settings, setIsScanningPrinters, setDiscoveredPrinters }) => {
  setIsScanningPrinters(true);
  setDiscoveredPrinters([]);

  const driver = String(settings.localPrinterDriver || 'brother').toLowerCase();

  if (driver === 'system') {
    setIsScanningPrinters(false);
    Alert.alert('System Print', 'System printing uses the OS print dialog. Use DIRECT for silent TCP printing.');
    return;
  }

  // -- Generic mDNS scan for direct/Brother/ZPL/RAW printers --
  try {
    const list = await discoverMdnsPrinters();
    setDiscoveredPrinters(list);
    if (list.length === 0) {
      Alert.alert('Printer Scan', 'No network printers found. You can still enter hostname manually.');
    }
  } catch (e) {
    console.log('scanForNetworkPrinters failed', e);
    Alert.alert('Printer Scan', 'Printer scan failed. Make sure native modules are installed in Android build.');
  } finally {
    setIsScanningPrinters(false);
  }
};
