import json
import re
import requests

OLLAMA_URL = "http://localhost:11434/api/generate"
MODEL_NAME = "llama3.2:3b-instruct-q4_0"


def extract_json(text):

    start = text.find("{")

    if start == -1:
        raise Exception(
            f"No JSON found:\n{text}"
        )

    candidate = text[start:]

    decoder = json.JSONDecoder()

    obj, _ = decoder.raw_decode(candidate)

    return obj



def llm_interpret(query):

    prompt = f"""
You are a BI reporting JSON API.

Rules:

1. Return valid JSON only.
2. Do not return markdown.
3. Do not return explanations.
4. Do not return code.
5. Return exactly one JSON object.

Available entities:

- farmer
- agent
- plot
- crop

Available metrics:

- count

Schema:

{{
  "entity":"",
  "report_type":"",
  "metric":"",
  "field":"",
  "group_by":"",
  "sort":"",
  "limit":null,
  "filters":{{}}
}}
# {{
#   "entity": "",
#   "metric": "",
#   "group_by": "",
#   "sort": "",
#   "field": "",
#   "limit": null,
#   "filters": {{}}
# }}

IMPORTANT:

If the question contains any of these words:

- count
- how many
- total
- sum
- top
- by district

then DO NOT return report_type="details".

Instead return an aggregate report using metric/group_by/sort/limit.

Only use report_type="details" when the user asks:
- show all
- list all
- details
- records

Examples:

Question:
Farmer count

Output:
{{
  "entity":"farmer",
  "metric":"count",
  "filters":{{}}
}}

Question:
Count farmers by district

Output:
{{
  "entity":"farmer",
  "metric":"count",
  "group_by":"district",
  "filters":{{}}
}}

Question:
District wise farmer count

Output:
{{
  "entity":"farmer",
  "metric":"count",
  "group_by":"district",
  "filters":{{}}
}}

Question:
Show all farmers

Output:
{{
  "entity":"farmer",
  "report_type":"details",
  "filters":{{}}
}}

Question:
Show all agents

Output:
{{
  "entity":"agent",
  "report_type":"details",
  "filters":{{}}
}}

Question:
Show all non geofenced plots

Output:
{{
  "entity":"plot",
  "report_type":"details",
  "filters":{{
      "geo_type":"non_geofenced"
  }}
}}

Question:
Show all geofenced plots

Output:
{{
  "entity":"plot",
  "report_type":"details",
  "filters":{{
      "geo_type":"geofenced"
  }}
}}

Question:
Show all farmers in Bolpur-Sriniketan

Output:
{{
  "entity":"farmer",
  "report_type":"details",
  "filters":{{
      "district":"Bolpur-Sriniketan"
  }}
}}

Question:
Show all plots in Labpur

Output:
{{
  "entity":"plot",
  "report_type":"details",
  "filters":{{
      "district":"Labpur"
  }}
}}

Question:
How many farmers are there?

Output:
{{
  "entity":"farmer",
  "metric":"count",
  "filters": {{}}
}}

Question:
How many agents are there?

Output:
{{
  "entity":"agent",
  "metric":"count",
  "filters": {{}}
}}

Question:
How many plots are there?

Output:
{{
  "entity":"plot",
  "metric":"count",
  "filters": {{}}
}}

Question:
How many farmers are there in Birbhum?

Output:
{{
  "entity":"farmer",
  "metric":"count",
  "filters": {{
    "district":"Birbhum"
  }}
}}

Question:
How many agents are there in Nadia?

Output:
{{
  "entity":"agent",
  "metric":"count",
  "filters": {{
    "district":"Nadia"
  }}
}}

Question:
Farmer count by district

Output:
{{
  "entity":"farmer",
  "metric":"count",
  "group_by":"district",
  "filters":{{}}
}}

Question:
Agent count by district

Output:
{{
  "entity":"agent",
  "metric":"count",
  "group_by":"district",
  "filters":{{}}
}}

Question:
Top 10 districts by farmer count

Output:
{{
  "entity":"farmer",
  "metric":"count",
  "group_by":"district",
  "sort":"desc",
  "limit":10,
  "filters":{{}}
}}

Question:
Top 5 districts by total area

Output:
{{
  "entity":"plot",
  "metric":"sum",
  "field":"land_size",
  "group_by":"district",
  "sort":"desc",
  "limit":5,
  "filters":{{}}
}}

Question:
How many farmers are there in Bolpur-Sriniketan?

Output:
{{
  "entity":"farmer",
  "metric":"count",
  "group_by":"",
  "filters": {{
      "district":"Bolpur-Sriniketan"
  }}
}}

Question:
Give me total non geofenced area

Output:
{{
  "entity":"plot",
  "metric":"sum",
  "field":"land_size",
  "filters": {{
      "geo_type":"non_geofenced"
  }}
}}

Question:
Give me total geofenced area

Output:
{{
  "entity":"plot",
  "metric":"sum",
  "field":"land_size",
  "filters": {{
      "geo_type":"geofenced"
  }}
}}

Question:
Total area by district

Output:
{{
  "entity":"plot",
  "metric":"sum",
  "field":"land_size",
  "group_by":"district",
  "filters":{{}}
}}

Question:
Top 10 districts by area

Output:
{{
  "entity":"plot",
  "metric":"sum",
  "field":"land_size",
  "group_by":"district",
  "sort":"desc",
  "limit":10,
  "filters":{{}}
}}

Question: Show all approved plots

{{
  "entity": "plot",
  "report_type": "details",
  "filters": {{
    "status_level": "APPROVED"
  }}
}}

Question: Show all rejected plots

{{
  "entity": "plot",
  "report_type": "details",
  "filters": {{
    "status_level": "REJECTED"
  }}
}}

Question: Show all pending plots

{{
  "entity": "plot",
  "report_type": "details",
  "filters": {{
    "status_level": "PENDING"
  }}
}}

Question: Show all carbon submitted plots

{{
  "entity": "plot",
  "report_type": "details",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_SUBMITTED"
  }}
}}

Question: Show all carbon rejected plots

{{
  "entity": "plot",
  "report_type": "details",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_REJECTED"
  }}
}}

Question: Show all carbon verified plots

{{
  "entity": "plot",
  "report_type": "details",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_APPROVED"
  }}
}}

Question: Total approved area

{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "APPROVED"
  }}
}}

Question: Total rejected area

{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "REJECTED"
  }}
}}

Question: Total pending area

{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "PENDING"
  }}
}}

Question: Total carbon submitted area

{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_SUBMITTED"
  }}
}}

Question: Total carbon rejected area

{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_REJECTED"
  }}
}}

Question: Total carbon verified area

{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_APPROVED"
  }}
}}

Question: How many approved plots

{{
  "entity": "plot",
  "metric": "count",
  "filters": {{
    "status_level": "APPROVED"
  }}
}}

Question: How many rejected plots

{{
  "entity": "plot",
  "metric": "count",
  "filters": {{
    "status_level": "REJECTED"
  }}
}}

Question: How many pending plots

{{
  "entity": "plot",
  "metric": "count",
  "filters": {{
    "status_level": "PENDING"
  }}
}}

Question: How many carbon submitted plots

{{
  "entity": "plot",
  "metric": "count",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_SUBMITTED"
  }}
}}

Question: How many carbon rejected plots

{{
  "entity": "plot",
  "metric": "count",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_REJECTED"
  }}
}}

Question: How many carbon verified plots

{{
  "entity": "plot",
  "metric": "count",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_APPROVED"
  }}
}}

Question: Show all carbon verified plots

{{
  "entity": "plot",
  "report_type": "details",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_APPROVED"
  }}
}}

Question: How many carbon verified plots

{{
  "entity": "plot",
  "report_type": "count",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_APPROVED"
  }}
}}

Question: Show approved plots in Labpur

{{
  "entity": "plot",
  "report_type": "details",
  "filters": {{
    "district": "Labpur",
    "status_level": "APPROVED"
  }}
}}

Question: Show carbon submitted plots in Labpur

{{
  "entity": "plot",
  "report_type": "details",
  "filters": {{
     "district": "Labpur",
    "status_level": "CARBON_DOCUMENTS_SUBMITTED"
  }}
}}

Question: Total approved area in Labpur

{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "district": "Labpur",
    "status_level": "APPROVED"
  }}
}}

Question: How many approved plots in Labpur

{{
  "entity": "plot",
  "metric": "count",
  "filters": {{
    "district": "Labpur",
    "status_level": "APPROVED"
  }}
}}

Question:
Give me all approved area

Response:
{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "APPROVED"
  }}
}}

Question:
Give me all pending area

Response:
{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "PENDING"
  }}
}}

Question:
Give me all Carbon Verified area

Response:
{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_APPROVED"
  }}
}}

Question:
Give me all Carbon Submitted area

Response:
{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_SUBMITTED"
  }}
}}

Question:
Give me all Carbon Rejected area

Response:
{{
  "entity": "plot",
  "metric": "sum",
  "field": "land_size",
  "filters": {{
    "status_level": "CARBON_DOCUMENTS_REJECTED"
  }}
}}

Question:
How many pipe installations?

Output:
{{
  "entity": "pipe",
  "metric": "count"
}}

Question:
Pipe installations by district

Output:
{{
  "entity": "pipe",
  "metric": "count",
  "group_by": "district"
}}

Question:
Total pipe installation area

Output:
{{
  "entity": "pipe",
  "metric": "sum",
  "field": "land_size"
}}

Question:
Pipe installation area by district

Output:
{{
  "entity": "pipe",
  "metric": "sum",
  "field": "land_size",
  "group_by": "district"
}}

Question:
Top districts by pipe installations

Output:
{{
  "entity": "pipe",
  "metric": "count",
  "group_by": "district",
  "top": 10
}}

Question:
Top districts by pipe installation area

Output:
{{
  "entity": "pipe",
  "metric": "sum",
  "field": "land_size",
  "group_by": "district",
  "top": 10
}}

Pipe installations by season

{{
  "entity": "pipe",
  "metric": "count",
  "group_by": "crop_season"
}}

Pipe area by season

{{
  "entity": "pipe",
  "metric": "sum",
  "field": "land_size",
  "group_by": "crop_season"
}}

Top seasons by pipe installations

{{
  "entity": "pipe",
  "metric": "count",
  "group_by": "crop_season",
  "sort": "desc",
  "limit": 10
}}

Top seasons by pipe area

{{
  "entity": "pipe",
  "metric": "sum",
  "field": "land_size",
  "group_by": "crop_season",
  "sort": "desc",
  "limit": 10
}}

}}


User Question:
{query}

JSON:
"""

    response = requests.post(
        OLLAMA_URL,
        json={
            "model": MODEL_NAME,
            "prompt": prompt,
            "stream": False,
            "options": {
                "temperature": 0
            }
        },
        timeout=180
    )

    response.raise_for_status()

    text = response.json()["response"]

    print("\nOLLAMA RESPONSE:")
    print(text)
    print("\n")

    try:

        parsed_json = extract_json(text)

        return {
            "success": True,
            "data": parsed_json,
            "raw_response": text
        }

    except Exception as e:

        return {
            "success": False,
            "error": str(e),
            "raw_response": text
        }    