from django.shortcuts import render
import cv2
import numpy as np
from matplotlib import pyplot as plt
from django.http import HttpResponse
from scipy import stats

from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from PIL import Image
import os

def crop_image(image, x, y, width, height):
    cropped_image = image[y:y+height, x:x+width]
    return cropped_image

def calculate_normalized_lbp_histogram(img_gray):
    height, width = img_gray.shape
    lbp_histogram = np.zeros(256, dtype=int)
    
    for i in range(1, height - 1):
        for j in range(1, width - 1):
            lbp_val = lbp_calculated_pixel(img_gray, i, j)
            lbp_histogram[lbp_val] += 1

    # Normalize the histogram
    lbp_histogram = lbp_histogram / sum(lbp_histogram)

    return lbp_histogram

def get_pixel(img, center, x, y):
    new_value = 0
    try:
        if img[x][y] >= center:
            new_value = 1
    except:
        pass
    return new_value

def lbp_calculated_pixel(img, x, y):
    center = img[x][y]
    val_ar = []
    val_ar.append(get_pixel(img, center, x-1, y-1))
    val_ar.append(get_pixel(img, center, x-1, y))
    val_ar.append(get_pixel(img, center, x-1, y + 1))
    val_ar.append(get_pixel(img, center, x, y + 1))
    val_ar.append(get_pixel(img, center, x + 1, y + 1))
    val_ar.append(get_pixel(img, center, x + 1, y))
    val_ar.append(get_pixel(img, center, x + 1, y-1))
    val_ar.append(get_pixel(img, center, x, y-1))
    power_val = [1, 2, 4, 8, 16, 32, 64, 128]
    val = 0
    for i in range(len(val_ar)):
        val += val_ar[i] * power_val[i]
    return val

def find_mode_pixel_value(img):
    img_flat = img.ravel()
    mode_value = int(np.median(img_flat))
    return mode_value

def calculate_lbp_image(img_gray):
    height, width = img_gray.shape
    lbp_image = np.zeros((height-2, width-2), dtype=np.uint8)
    
    for i in range(1, height - 1):
        for j in range(1, width - 1):
            lbp_val = lbp_calculated_pixel(img_gray, i, j)
            lbp_image[i-1, j-1] = lbp_val

    return lbp_image

def save_lbp_to_txt(lbp_image, filename):
    with open(filename, 'w') as f:
        for row in lbp_image:
            row_str = ' '.join(map(str, row))
            f.write(row_str + '\n')

def save_normalized_lbp_histogram_to_txt(lbp_histogram, filename):
    with open(filename, 'w') as f:
        for bin_val, freq in enumerate(lbp_histogram):
            f.write(f"LBP Code: {bin_val}, Normalized Frequency: {freq}\n")

def find_mode_lbp_histogram(lbp_histogram):
    mode_value = np.argmax(lbp_histogram)
    mode_frequency = lbp_histogram[mode_value]
    return mode_value, mode_frequency

# Definisi kriteria penilaian kesuburan tanah dalam bentuk dictionary
kriteria_kesuburan_tanah = {
    "KT001": "Sangat Rendah",
    "KT002": "Rendah",
    "KT003": "Sedang",
    "KT004": "Tinggi",
    "KT005": "Sangat Tinggi"
}

# Definisi sifat tanah berdasarkan rentang kadar NPK
sifat_tanah_npk = {
    "NKT001": ("Nitrogen Sangat Rendah", 0.00, 0.10),
    "NKT002": ("Nitrogen Rendah", 0.10, 0.20),
    "NKT003": ("Nitrogen Sedang", 0.21, 0.50),
    "NKT004": ("Nitrogen Tinggi", 0.51, 0.75),
    "NKT005": ("Nitrogen Sangat Tinggi", 0.76, float("inf")),
    "FKT001": ("Fosfor Sangat Rendah", 0, 15),
    "FKT002": ("Fosfor Rendah", 15, 20),
    "FKT003": ("Fosfor Sedang", 21, 40),
    "FKT004": ("Fosfor Tinggi", 41, 60),
    "FKT005": ("Fosfor Sangat Tinggi", 61, float("inf")),
    "KKT001": ("Kalium Sangat Rendah", 0, 10),
    "KKT002": ("Kalium Rendah", 10, 20),
    "KKT003": ("Kalium Sedang", 21, 40),
    "KKT004": ("Kalium Tinggi", 41, 60),
    "KKT005": ("Kalium Sangat Tinggi", 61, float("inf"))
}

# Definisi rekomendasi tanaman berdasarkan tingkat kesesuaian tanah
rekomendasi_tanaman = {
    "R001": "Kategori S1 Sangat Sesuai Untuk Ditanami Padi Sawah Irigasi, Wortel, Bawang Merah, Bawang Putih",
    "R002": "Kategori S2 Cukup Sesuai (Sedang) Untuk Ditanami Padi Sawah Irigasi, Wortel, Bawang Merah, Bawang Putih",
    "R003": "Kategori S3 Sesuai Marginal (Rendah) Untuk Ditanami Sawah Irigasi, Wortel, Bawang Merah, Bawang Putih",
    "R004": "Kategori S1 Sangat Sesuai Untuk Ditanami Jagung, Sorgum, Gandum, Kedelai, Kacang Tanah, Tebu",
    "R005": "Kategori S2 Cukup Sesuai (Sedang) Untuk Ditanami Jagung, Sorgum, Gandum, Kedelai, Kacang Tanah, Tebu",
    "R006": "Kategori S3 Sesuai Marginal (Rendah) Untuk Ditanami Jagung, Sorgum, Gandum, Kedelai, Kacang Tanah, Tebu",
    "R007": "Kategori S1 Sangat Sesuai Untuk ditanami Ubi Kayu, Ubi Jalar",
    "R008": "Kategori S2 Cukup Sesuai (Sedang) Untuk ditanami Ubi Kayu, Ubi Jalar",
    "R009": "Kategori S3 Sesuai Marginal (Rendah) Untuk ditanami Ubi Kayu, Ubi Jalar",
    "R010": "Kategori S1 Sangat Sesuai Untuk Ditanami Kakao, Kapas, Kayu Manis, Vanili",
    "R011": "Kategori S2 Cukup Sesuai (Sedang) Untuk Ditanami Kakao, Kapas, Kayu Manis, Vanili",
    "R012": "Kategori S3 Sesuai Marginal (Rendah) Untuk Ditanami Kakao, Kapas, Kayu Manis, Vanili"
}

# Definisi aturan rekomendasi tanaman
rule_rekomendasi = {
    ("NKT003", "FKT004", "KKT003"): "R001",
    ("NKT002", "FKT003", "KKT002"): "R002",
    ("NKT001", "FKT002", "KKT003"): "R003",
    ("NKT001", "FKT001", "KKT003"): "R003",
    ("NKT003", "FKT004", "KKT004"): "R004",
    ("NKT002", "FKT003", "KKT002"): "R005",
    ("NKT001", "FKT002", "KKT001"): "R006",
    ("NKT001", "FKT001", "KKT002"): "R006",
    ("NKT001", "FKT002", "KKT002"): "R006",
    ("NKT001", "FKT001", "KKT001"): "R006",
    ("NKT003", "FKT003", "KKT003"): "R007",
    ("NKT002", "FKT002", "KKT002"): "R008",
    ("NKT001", "FKT001", "KKT001"): "R009",
    ("NKT003", "FKT003", "KKT004"): "R010",
    ("NKT002", "FKT002", "KKT003"): "R011",
    ("NKT002", "FKT001", "KKT003"): "R011",
    ("NKT001", "FKT001", "KKT002"): "R012",
    ("NKT001", "FKT001", "KKT001"): "R012"
    
}

# Fungsi untuk mendapatkan sifat tanah berdasarkan kadar
def get_sifat_tanah(kadar, jenis):
    for kode, (sifat, min_val, max_val) in sifat_tanah_npk.items():
        if jenis in kode and min_val <= kadar <= max_val:
            return kode
    return None

# Fungsi untuk mendapatkan rekomendasi tanaman
def get_rekomendasi(nitrogen, fosfor, kalium):
    kode_n = get_sifat_tanah(nitrogen, "NKT")
    kode_f = get_sifat_tanah(fosfor, "FKT")
    kode_k = get_sifat_tanah(kalium, "KKT")
    
    rekomendasi = rule_rekomendasi.get((kode_n, kode_f, kode_k), "Tidak ada rekomendasi yang sesuai")
    return rekomendasi_tanaman.get(rekomendasi, "Tidak ada rekomendasi")


def lbp(request):
    # Proses Memasukkan Image
    path = 'media/lahan 5 50cm.jpeg'
    img_bgr = cv2.imread(path, 1)
    plt.imshow(cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB))
    plt.title('Original Image')
    plt.axis('off')  # Tidak menampilkan sumbu x dan y
    plt.show()
    
    # Melakukan Cropping Image
    # Tentukan koordinat titik awal dan dimensi untuk cropping
    x = 0  # Koordinat x titik awal
    y = 0  # Koordinat y titik awal
    width = 640  # Lebar area yang akan dipotong
    height = 480  # Tinggi area yang akan dipotong
    
    # Lakukan cropping pada gambar
    cropped_image = crop_image(img_bgr, x, y, width, height)  # Ganti nilai x, y, width, dan height sesuai kebutuhan
    plt.imshow(cv2.cvtColor(cropped_image, cv2.COLOR_BGR2RGB))
    plt.title('Preview Gambar Crop 640 * 480 Pixel')
    plt.axis('off')  # Tidak menampilkan sumbu x dan y
    plt.show()

    # Konversi Image Ke Grayscale
    img_gray = cv2.cvtColor(cropped_image, cv2.COLOR_BGR2GRAY)
    plt.imshow(img_gray, cmap='gray')
    plt.title('Grayscale Image')
    plt.axis('off')
    plt.show()

    
    # Equalisasi histogram Gaussian Blur 
    equalized_image = cv2.equalizeHist(img_gray)

    # Filter tapis (Gaussian Blur)
    blurred_image = cv2.GaussianBlur(equalized_image, (5, 5), 0)

    # Menampilkan gambar hasil Gaussian Blur
    plt.imshow(blurred_image, cmap='gray')
    plt.title('Blurred Image (Gaussian Blur)')
    plt.axis('off')
    plt.show()

   # Hitung dan tampilkan gambar LBP
    lbp_image = calculate_lbp_image(blurred_image)
    plt.imshow(lbp_image, cmap='gray')
    plt.title('LBP Image')
    plt.axis('off')
    plt.show()

    # Simpan hasil LBP ke file teks
    save_lbp_to_txt(lbp_image, 'media/lbp_result.txt')
    print("Hasil LBP telah disimpan dalam file 'lbp_result.txt'")
   
    # Hitung histogram normalisasi LBP
    lbp_histogram = calculate_normalized_lbp_histogram(blurred_image)

    plt.figure(figsize=(10, 6))
    plt.bar(range(len(lbp_histogram)), lbp_histogram, color='b', width=1)
    plt.title('Normalized LBP Histogram')
    plt.xlabel('LBP Code')
    plt.ylabel('Normalized Frequency')
    plt.grid(True)
    plt.show()

    # Simpan histogram normalisasi LBP ke file teks
    save_normalized_lbp_histogram_to_txt(lbp_histogram, 'media/lbp_normalized_histogram.txt')
    print("Histogram normalisasi LBP telah disimpan dalam file 'lbp_normalized_histogram.txt'")

    # Temukan nilai yang paling sering muncul dalam histogram
    mode_lbp_value, mode_lbp_frequency = find_mode_lbp_histogram(lbp_histogram)
    print(f"Nilai histogram normalisasi yang paling sering muncul: {mode_lbp_value}")
    print(f"Frekuensi ternormalisasi dari nilai yang paling sering muncul: {mode_lbp_frequency}")
    # Hitung kadar NPK berdasarkan mode LBP frequency
    hasil_operasi_Natrium = mode_lbp_frequency * 0.1928 + 0.021
    nitrogen = round(hasil_operasi_Natrium, 2)
    print(f"Hasil Nilai N (Nitrogen): {nitrogen}")

    hasil_operasi_fosfor = (mode_lbp_frequency * -10.725) + 16.533
    fosfor = round(hasil_operasi_fosfor, 2)
    print(f"Hasil Nilai P (Fosfor): {fosfor}")

    hasil_operasi_Kalium = mode_lbp_frequency * -0.1864 + 0.2471
    kalium = round(hasil_operasi_Kalium, 2)
    print(f"Hasil Nilai K (Kalium): {kalium}")

    # Analisis sifat tanah berdasarkan kadar NPK
    sifat_nitrogen = get_sifat_tanah(nitrogen, "NKT")
    sifat_fosfor = get_sifat_tanah(fosfor, "FKT")
    sifat_kalium = get_sifat_tanah(kalium, "KKT")

    print(f"Sifat tanah berdasarkan kadar Nitrogen: {sifat_tanah_npk.get(sifat_nitrogen, ('Tidak ditemukan',))[0]}")
    print(f"Sifat tanah berdasarkan kadar Fosfor: {sifat_tanah_npk.get(sifat_fosfor, ('Tidak ditemukan',))[0]}")
    print(f"Sifat tanah berdasarkan kadar Kalium: {sifat_tanah_npk.get(sifat_kalium, ('Tidak ditemukan',))[0]}")

    # Menampilkan rekomendasi tanaman
    rekomendasi = get_rekomendasi(nitrogen, fosfor, kalium)
    print(f"Rekomendasi tanaman: {rekomendasi}")

lbp(None)

