using System.Collections;
using UnityEngine;
using Unity.Barracuda;
using TMPro;
using UnityEngine.SceneManagement;
using UnityEngine.UI; // Untuk komponen Image

public class AcakClassifier : MonoBehaviour
{
    [Header("Model Barracuda")]
    public NNModel onnxModel;
    private Model runtimeModel;
    private IWorker worker;

    [Header("UI Text")]
    public TextMeshProUGUI outputText;
    public TextMeshProUGUI scoreText;
    public TextMeshProUGUI titleText;
    public TextMeshProUGUI descriptionText;

    [Header("UI Image")]
    public Image displayImage; // Menampilkan foto hasil kamera

    [Header("Initial Display Sprites")]
    public Sprite organikSprite;
    public Sprite anorganikSprite;
    public Sprite bukansampahSprite;

    [Header("Feedback Images")]
    public Image feedbackCorrectImage;
    public Image feedbackWrongImage;
    public float feedbackDelay = 0.5f;

    [Header("Canvas")]
    public GameObject canvasBerhasil;
    public GameObject canvasGagal;

    [Header("Audio")]
    [SerializeField] private AudioSource audioSource;
    [SerializeField] private AudioClip correctClip;
    [SerializeField] private AudioClip wrongClip;
    [SerializeField] private AudioClip awardClip;

    private string[] classes = { "anorganik", "bukansampah", "organik" };

    private string[] scenarioSequence;
    private int currentIndex = 0;

    private int inputWidth = 224;
    private int inputHeight = 224;

    private int currentScore = 0;
    private int maxScore = 0;

    void Start()
    {
        runtimeModel = ModelLoader.Load(onnxModel);
        worker = WorkerFactory.CreateWorker(WorkerFactory.Type.Auto, runtimeModel);

        int selectedLevel = PlayerPrefs.GetInt("selectedLevel", 1);
        Debug.Log("Selected Level: " + selectedLevel);

        // Set target quest sesuai level yang dipilih
        switch (selectedLevel)
        {
            case 1:
                scenarioSequence = new string[] { "organik" };
                break;
            case 2:
                scenarioSequence = new string[] { "bukansampah" };
                break;
            case 3:
                scenarioSequence = new string[] { "anorganik" };
                break;
            case 4:
                scenarioSequence = new string[] { "bukansampah" };
                break;
            case 5:
                scenarioSequence = new string[] { "anorganik" };
                break;
            case 6:
                scenarioSequence = new string[] { "organik" };
                break;
            default:
                scenarioSequence = new string[] { "organik" };
                break;
        }

        maxScore = scenarioSequence.Length;

        if (feedbackCorrectImage != null)
            feedbackCorrectImage.gameObject.SetActive(false);
        if (feedbackWrongImage != null)
            feedbackWrongImage.gameObject.SetActive(false);

        UpdateUI();
        UpdateScoreText();
    }

    private void UpdateUI()
    {
        if (currentIndex >= scenarioSequence.Length)
        {
            titleText.text = "SELESAI!";
            descriptionText.text = "Kamu sudah menemukan target.";
            return;
        }

        string target = scenarioSequence[currentIndex];
        switch (target)
        {
            case "organik":
                titleText.text = "JELAJAHI SAMPAH ORGANIK";
                descriptionText.text = "Cari sampah organik, misalnya kulit buah.";
                if (displayImage != null && organikSprite != null)
                    displayImage.sprite = organikSprite;
                break;
            case "anorganik":
                titleText.text = "JELAJAHI SAMPAH ANORGANIK";
                descriptionText.text = "Cari sampah anorganik, misalnya botol plastik.";
                if (displayImage != null && anorganikSprite != null)
                    displayImage.sprite = anorganikSprite;
                break;
            case "bukansampah":
                titleText.text = "JELAJAHI OBJEK BUKAN SAMPAH";
                descriptionText.text = "Cari objek non-sampah, misalnya buah apel atau jeruk.";
                if (displayImage != null && bukansampahSprite != null)
                    displayImage.sprite = bukansampahSprite;
                break;
        }
    }

    public void TakePicture()
    {
        NativeCamera.Permission permission = NativeCamera.CheckPermission(true);
        if (permission == NativeCamera.Permission.Denied || permission == NativeCamera.Permission.ShouldAsk)
        {
            NativeCamera.RequestPermission(true);
        }

        NativeCamera.TakePicture((path) =>
        {
            if (!string.IsNullOrEmpty(path))
            {
                Texture2D texture = NativeCamera.LoadImageAtPath(path, inputWidth);
                if (texture == null)
                {
                    Debug.LogError("Gagal memuat gambar dari path: " + path);
                    return;
                }
                Texture2D readableTexture = MakeTextureReadable(texture);
                Texture2D correctedTexture = CorrectCameraImage(readableTexture);

                if (displayImage != null)
                {
                    Sprite newSprite = Sprite.Create(correctedTexture,
                        new Rect(0, 0, correctedTexture.width, correctedTexture.height),
                        new Vector2(0.5f, 0.5f));
                    displayImage.sprite = newSprite;
                }

                RunInference(correctedTexture);
            }
        }, maxSize: inputWidth);
    }

    public void RunInference(Texture2D inputTexture)
    {
        if (inputTexture == null)
        {
            Debug.LogError("Gambar tidak tersedia untuk inferensi!");
            return;
        }

        Texture2D resized = ResizeTexture(inputTexture, inputWidth, inputHeight);
        Color32[] pixels = resized.GetPixels32();
        float[] floatValues = new float[inputWidth * inputHeight * 3];

        for (int i = 0; i < pixels.Length; i++)
        {
            floatValues[i * 3 + 0] = (pixels[i].r / 127.5f) - 1.0f;
            floatValues[i * 3 + 1] = (pixels[i].g / 127.5f) - 1.0f;
            floatValues[i * 3 + 2] = (pixels[i].b / 127.5f) - 1.0f;
        }

        Tensor inputTensor = new Tensor(1, inputHeight, inputWidth, 3, floatValues);
        worker.Execute(inputTensor);
        Tensor outputTensor = worker.PeekOutput();

        float[] scores = outputTensor.ToReadOnlyArray();
        int predictedIndex = ArgMax(scores);
        float confidence = scores[predictedIndex];
        string predictedClass = classes[predictedIndex];

        Debug.Log($"Predicted Class: {predictedClass}\nConfidence: {confidence:F2}");
        if (outputText != null)
        {
            outputText.text = $"Predicted Class: {predictedClass}\nConfidence: {confidence:F2}";
        }

        // Cek apakah prediksi sesuai dengan target
        if (currentIndex < scenarioSequence.Length)
        {
            string currentTarget = scenarioSequence[currentIndex];
            if (predictedClass == currentTarget)
            {
                currentScore++;
                if (audioSource != null && correctClip != null)
                {
                    audioSource.PlayOneShot(correctClip);
                }
                currentIndex++;

                if (currentIndex >= scenarioSequence.Length)
                {
                    StartCoroutine(ShowFeedback(true, true));
                }
                else
                {
                    StartCoroutine(ShowFeedback(true, false));
                }
            }
            else
            {
                if (audioSource != null && wrongClip != null)
                {
                    audioSource.PlayOneShot(wrongClip);
                }
                // Jawaban salah, tampilkan feedback lalu canvas gagal
                StartCoroutine(ShowFeedback(false, true));
            }
        }

        inputTensor.Dispose();
        outputTensor.Dispose();
    }

    private IEnumerator ShowFeedback(bool isCorrect, bool isFinal)
    {
        if (isCorrect)
        {
            if (feedbackCorrectImage != null)
                feedbackCorrectImage.gameObject.SetActive(true);
        }
        else
        {
            if (feedbackWrongImage != null)
                feedbackWrongImage.gameObject.SetActive(true);
        }

        yield return new WaitForSeconds(feedbackDelay);

        if (isCorrect)
        {
            if (feedbackCorrectImage != null)
                feedbackCorrectImage.gameObject.SetActive(false);
        }
        else
        {
            if (feedbackWrongImage != null)
                feedbackWrongImage.gameObject.SetActive(false);
        }

        // Jika isFinal true, tampilkan canvas hasil dan (jika benar) unlock level berikutnya
        if (isFinal)
        {
            if (isCorrect)
            {
                int selectedLevel = PlayerPrefs.GetInt("selectedLevel", 1);
                int maxLevelUnlocked = PlayerPrefs.GetInt("maxLevelUnlocked", 1);
                if (selectedLevel >= maxLevelUnlocked)
                {
                    PlayerPrefs.SetInt("maxLevelUnlocked", selectedLevel + 1);
                }

                if (audioSource != null && awardClip != null)
                {
                    audioSource.PlayOneShot(awardClip);
                }

                if (canvasBerhasil != null)
                    canvasBerhasil.SetActive(true);
            }
            else
            {
                if (canvasGagal != null)
                    canvasGagal.SetActive(true);
            }
        }
        else
        {
            UpdateUI();
        }
    }

    private int ArgMax(float[] array)
    {
        int index = 0;
        float max = array[0];
        for (int i = 1; i < array.Length; i++)
        {
            if (array[i] > max)
            {
                max = array[i];
                index = i;
            }
        }
        return index;
    }

    private Texture2D ResizeTexture(Texture2D source, int newWidth, int newHeight)
    {
        RenderTexture rt = RenderTexture.GetTemporary(newWidth, newHeight);
        RenderTexture.active = rt;
        Graphics.Blit(source, rt);
        Texture2D newTexture = new Texture2D(newWidth, newHeight);
        newTexture.ReadPixels(new Rect(0, 0, newWidth, newHeight), 0, 0);
        newTexture.Apply();
        RenderTexture.active = null;
        RenderTexture.ReleaseTemporary(rt);
        return newTexture;
    }

    private Texture2D MakeTextureReadable(Texture2D tex)
    {
        RenderTexture tmp = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear);
        Graphics.Blit(tex, tmp);
        RenderTexture previous = RenderTexture.active;
        RenderTexture.active = tmp;
        Texture2D readableTex = new Texture2D(tex.width, tex.height);
        readableTex.ReadPixels(new Rect(0, 0, tmp.width, tmp.height), 0, 0);
        readableTex.Apply();
        RenderTexture.active = previous;
        RenderTexture.ReleaseTemporary(tmp);
        return readableTex;
    }

    private Texture2D CorrectCameraImage(Texture2D original)
    {
        int width = original.width;
        int height = original.height;
        Texture2D rotated = new Texture2D(height, width, original.format, false);
        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                rotated.SetPixel(j, width - i - 1, original.GetPixel(i, j));
            }
        }
        rotated.Apply();
        return rotated;
    }

    private void UpdateScoreText()
    {
        int selectedLevel = PlayerPrefs.GetInt("selectedLevel", 1);
        if (scoreText != null)
        {
            scoreText.text = "Level " + selectedLevel;
        }
    }

    private void OnDestroy()
    {
        worker?.Dispose();
    }
}
