import AsyncStorage from '@react-native-async-storage/async-storage';
import NetInfo from '@react-native-community/netinfo';
import Constants from 'expo-constants';
import * as Device from 'expo-device';
import { Platform } from 'react-native';
import { ConstEnv } from '@/constants/ConstEnv';

const QUEUE_KEY = 'error_log_queue';
const APP_NAME = 'desa-plus';

type ErrorPayload = {
  affectedVersion: string;
  device: string;
  os: string;
  description: string;
  app: string;
  source: 'SYSTEM';
  stackTrace: string;
};

function buildPayload(description: string, stackTrace?: string): ErrorPayload {
  const platformName = Platform.OS === 'ios' ? 'iOS' : 'Android';
  return {
    affectedVersion: Constants.expoConfig?.version ?? 'unknown',
    device: Device.modelName ?? 'unknown',
    os: `${platformName} ${Device.osVersion ?? ''}`.trim(),
    description,
    app: APP_NAME,
    source: 'SYSTEM',
    stackTrace: stackTrace ?? '',
  };
}

async function sendToMonitoring(payload: ErrorPayload): Promise<boolean> {
  try {
    const res = await fetch(`${ConstEnv.url_monitoring}/api/bugs`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-API-Key': ConstEnv.key_api_monitoring ?? '',
      },
      body: JSON.stringify(payload),
    });
    return res.ok;
  } catch (error) {
    console.log(error);
    return false;
  }
}

async function enqueue(payload: ErrorPayload): Promise<void> {
  try {
    const raw = await AsyncStorage.getItem(QUEUE_KEY);
    const queue: ErrorPayload[] = raw ? JSON.parse(raw) : [];
    queue.push(payload);
    await AsyncStorage.setItem(QUEUE_KEY, JSON.stringify(queue));
  } catch {}
}

export async function flushErrorQueue(): Promise<void> {
  try {
    const state = await NetInfo.fetch();
    if (!state.isConnected) return;

    const raw = await AsyncStorage.getItem(QUEUE_KEY);
    if (!raw) return;

    const queue: ErrorPayload[] = JSON.parse(raw);
    if (queue.length === 0) return;

    const failed: ErrorPayload[] = [];
    for (const payload of queue) {
      const ok = await sendToMonitoring(payload);
      if (!ok) failed.push(payload);
    }

    if (failed.length > 0) {
      await AsyncStorage.setItem(QUEUE_KEY, JSON.stringify(failed));
    } else {
      await AsyncStorage.removeItem(QUEUE_KEY);
    }
  } catch {}
}

export async function logError(description: string, error?: Error | unknown): Promise<void> {
  const stackTrace = error instanceof Error ? (error.stack ?? error.message) : String(error ?? '');
  const payload = buildPayload(description, stackTrace);

  try {
    const state = await NetInfo.fetch();
    if (state.isConnected) {
      const ok = await sendToMonitoring(payload);
      if (!ok) await enqueue(payload);
    } else {
      await enqueue(payload);
    }
  } catch {
    await enqueue(payload);
  }
}
