/**
 * Barcode Scanner Service
 *
 * Handles barcode/QR code scanning with camera
 */

import { Camera, CameraType, BarcodeScanningResult } from 'expo-camera';
import * as Haptics from 'expo-haptics';

// Supported barcode types
export type BarcodeType =
  | 'qr'
  | 'ean13'
  | 'ean8'
  | 'code128'
  | 'code39'
  | 'code93'
  | 'upc_a'
  | 'upc_e'
  | 'pdf417'
  | 'aztec'
  | 'datamatrix';

// Barcode format mapping to expo-camera types
export const BARCODE_TYPES: Record<BarcodeType, string> = {
  qr: 'qr',
  ean13: 'ean13',
  ean8: 'ean8',
  code128: 'code128',
  code39: 'code39',
  code93: 'code93',
  upc_a: 'upc_a',
  upc_e: 'upc_e',
  pdf417: 'pdf417',
  aztec: 'aztec',
  datamatrix: 'datamatrix',
};

// Scanned barcode result
export interface ScannedBarcode {
  type: string;
  data: string;
  timestamp: number;
  cornerPoints?: { x: number; y: number }[];
}

// Parsed product barcode
export interface ProductBarcode {
  code: string;
  type: 'ean13' | 'ean8' | 'upc_a' | 'upc_e' | 'other';
  isValid: boolean;
}

// Parsed QR data types
export interface ParsedQRData {
  type: 'url' | 'product' | 'invoice' | 'partner' | 'text' | 'json';
  data: Record<string, any>;
  raw: string;
}

// Barcode service
export const barcodeService = {
  // Check camera permission status
  checkPermission: async (): Promise<{
    granted: boolean;
    canAskAgain: boolean;
  }> => {
    const { status, canAskAgain } = await Camera.getCameraPermissionsAsync();
    return {
      granted: status === 'granted',
      canAskAgain: canAskAgain ?? true,
    };
  },

  // Request camera permission
  requestPermission: async (): Promise<boolean> => {
    const { status } = await Camera.requestCameraPermissionsAsync();
    return status === 'granted';
  },

  // Provide haptic feedback on scan
  vibrate: async (): Promise<void> => {
    await Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
  },

  // Validate EAN-13 barcode
  validateEAN13: (code: string): boolean => {
    if (!/^\d{13}$/.test(code)) return false;

    let sum = 0;
    for (let i = 0; i < 12; i++) {
      sum += parseInt(code[i], 10) * (i % 2 === 0 ? 1 : 3);
    }
    const checkDigit = (10 - (sum % 10)) % 10;
    return parseInt(code[12], 10) === checkDigit;
  },

  // Validate EAN-8 barcode
  validateEAN8: (code: string): boolean => {
    if (!/^\d{8}$/.test(code)) return false;

    let sum = 0;
    for (let i = 0; i < 7; i++) {
      sum += parseInt(code[i], 10) * (i % 2 === 0 ? 3 : 1);
    }
    const checkDigit = (10 - (sum % 10)) % 10;
    return parseInt(code[7], 10) === checkDigit;
  },

  // Validate UPC-A barcode
  validateUPCA: (code: string): boolean => {
    if (!/^\d{12}$/.test(code)) return false;

    let sum = 0;
    for (let i = 0; i < 11; i++) {
      sum += parseInt(code[i], 10) * (i % 2 === 0 ? 3 : 1);
    }
    const checkDigit = (10 - (sum % 10)) % 10;
    return parseInt(code[11], 10) === checkDigit;
  },

  // Parse product barcode
  parseProductBarcode: (code: string, type: string): ProductBarcode => {
    const normalizedCode = code.trim();
    const normalizedType = type.toLowerCase();

    if (normalizedType === 'ean13' || normalizedCode.length === 13) {
      return {
        code: normalizedCode,
        type: 'ean13',
        isValid: barcodeService.validateEAN13(normalizedCode),
      };
    }

    if (normalizedType === 'ean8' || normalizedCode.length === 8) {
      return {
        code: normalizedCode,
        type: 'ean8',
        isValid: barcodeService.validateEAN8(normalizedCode),
      };
    }

    if (normalizedType === 'upc_a' || normalizedCode.length === 12) {
      return {
        code: normalizedCode,
        type: 'upc_a',
        isValid: barcodeService.validateUPCA(normalizedCode),
      };
    }

    if (normalizedType === 'upc_e' || normalizedCode.length === 8) {
      return {
        code: normalizedCode,
        type: 'upc_e',
        isValid: true, // UPC-E validation is complex
      };
    }

    return {
      code: normalizedCode,
      type: 'other',
      isValid: true,
    };
  },

  // Parse QR code data
  parseQRData: (data: string): ParsedQRData => {
    const trimmedData = data.trim();

    // Check if URL
    if (trimmedData.match(/^https?:\/\//i)) {
      const url = new URL(trimmedData);

      // Check for app deep links
      if (url.pathname.includes('/product/')) {
        const productId = url.pathname.split('/product/')[1];
        return {
          type: 'product',
          data: { id: productId, url: trimmedData },
          raw: data,
        };
      }

      if (url.pathname.includes('/invoice/')) {
        const invoiceId = url.pathname.split('/invoice/')[1];
        return {
          type: 'invoice',
          data: { id: invoiceId, url: trimmedData },
          raw: data,
        };
      }

      if (url.pathname.includes('/partner/')) {
        const partnerId = url.pathname.split('/partner/')[1];
        return {
          type: 'partner',
          data: { id: partnerId, url: trimmedData },
          raw: data,
        };
      }

      return {
        type: 'url',
        data: { url: trimmedData },
        raw: data,
      };
    }

    // Check if JSON
    try {
      const json = JSON.parse(trimmedData);

      // Check for known JSON structures
      if (json.productId || json.product_id) {
        return {
          type: 'product',
          data: json,
          raw: data,
        };
      }

      if (json.invoiceId || json.invoice_id || json.invoiceNumber) {
        return {
          type: 'invoice',
          data: json,
          raw: data,
        };
      }

      if (json.partnerId || json.partner_id || json.customerId) {
        return {
          type: 'partner',
          data: json,
          raw: data,
        };
      }

      return {
        type: 'json',
        data: json,
        raw: data,
      };
    } catch {
      // Not JSON
    }

    // Check for app-specific prefixes
    if (trimmedData.startsWith('PROD:')) {
      return {
        type: 'product',
        data: { code: trimmedData.substring(5) },
        raw: data,
      };
    }

    if (trimmedData.startsWith('INV:')) {
      return {
        type: 'invoice',
        data: { number: trimmedData.substring(4) },
        raw: data,
      };
    }

    if (trimmedData.startsWith('PARTNER:')) {
      return {
        type: 'partner',
        data: { id: trimmedData.substring(8) },
        raw: data,
      };
    }

    // Default to text
    return {
      type: 'text',
      data: { text: trimmedData },
      raw: data,
    };
  },

  // Convert expo-camera result to ScannedBarcode
  convertScanResult: (result: BarcodeScanningResult): ScannedBarcode => ({
    type: result.type,
    data: result.data,
    timestamp: Date.now(),
    cornerPoints: result.cornerPoints,
  }),
};

// Default barcode types for product scanning
export const PRODUCT_BARCODE_TYPES: BarcodeType[] = [
  'ean13',
  'ean8',
  'upc_a',
  'upc_e',
  'code128',
  'code39',
];

// All supported barcode types
export const ALL_BARCODE_TYPES: BarcodeType[] = Object.keys(BARCODE_TYPES) as BarcodeType[];
