#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import argparse
import csv
import json
import os
import subprocess
import sys
import time
import urllib.parse
import urllib.request
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parents[1]
CSV_PATH = BASE_DIR / "data" / "food_log.csv"
OFFSET_PATH = BASE_DIR / "data" / "telegram_offset.txt"
TOKEN_PATH = Path(os.environ.get(
    "HEALTH_INPUT_BOT_TOKEN_PATH",
    str(Path.home() / ".credentials" / "health_input_bot_telegram_token")
))

PROCESS_TEXT = BASE_DIR / "scripts" / "process_text.py"


def read_token():
    token = TOKEN_PATH.read_text(encoding="utf-8").strip()
    if not token:
        raise RuntimeError("Telegram token file is empty")
    return token


def api_call(token, method, params=None, timeout=40):
    params = params or {}
    url = f"https://api.telegram.org/bot{token}/{method}"
    data = urllib.parse.urlencode(params).encode("utf-8")
    req = urllib.request.Request(url, data=data)
    with urllib.request.urlopen(req, timeout=timeout) as resp:
        payload = json.loads(resp.read().decode("utf-8"))
    if not payload.get("ok"):
        raise RuntimeError(f"Telegram API error: {payload}")
    return payload["result"]


def load_offset():
    try:
        return int(OFFSET_PATH.read_text(encoding="utf-8").strip())
    except Exception:
        return None


def save_offset(offset):
    OFFSET_PATH.parent.mkdir(parents=True, exist_ok=True)
    OFFSET_PATH.write_text(str(offset), encoding="utf-8")


def get_updates(token):
    params = {
        "timeout": 25,
        "allowed_updates": json.dumps(["message"], ensure_ascii=False),
    }
    offset = load_offset()
    if offset is not None:
        params["offset"] = offset
    return api_call(token, "getUpdates", params=params, timeout=35)


def send_message(token, chat_id, text):
    return api_call(token, "sendMessage", {
        "chat_id": chat_id,
        "text": text,
        "disable_web_page_preview": True,
    }, timeout=20)


def read_csv_rows():
    if not CSV_PATH.exists():
        return []
    with CSV_PATH.open("r", encoding="utf-8", newline="") as f:
        reader = csv.DictReader(f)
        return list(reader)


def fmt_num(value):
    try:
        n = float(value)
        if n.is_integer():
            return str(int(n))
        return f"{n:.1f}".rstrip("0").rstrip(".")
    except Exception:
        return str(value)


def source_label(src):
    if src == "openclaw_agent":
        return "OpenClaw"
    if src == "deterministic_fallback":
        return "Fallback"
    if src == "openai":
        return "OpenAI"
    if src == "ai_agent":
        return "AI"
    return src or "לא ידוע"


def build_success_reply(new_rows):
    if not new_rows:
        return "נרשם ✅"

    lines = ["נרשם ✅"]

    if len(new_rows) == 1:
        r = new_rows[0]
        food = r.get("food_name", "")
        qty = fmt_num(r.get("quantity", ""))
        unit = r.get("unit", "")
        cal = fmt_num(r.get("calories", "0"))
        protein = fmt_num(r.get("protein_g", "0"))
        fat = fmt_num(r.get("fat_g", "0"))
        src = source_label(r.get("parser_source", ""))

        lines.append(f"{food} - {qty}{unit}")
        lines.append(f"{cal} קלוריות | {protein}g חלבון | {fat}g שומן")
        lines.append(f"מקור: {src}")
        return "\n".join(lines)

    total_cal = 0.0
    total_protein = 0.0
    total_fat = 0.0
    src_values = []

    for i, r in enumerate(new_rows, start=1):
        food = r.get("food_name", "")
        qty = fmt_num(r.get("quantity", ""))
        unit = r.get("unit", "")
        cal = fmt_num(r.get("calories", "0"))
        protein = fmt_num(r.get("protein_g", "0"))
        fat = fmt_num(r.get("fat_g", "0"))
        src_values.append(r.get("parser_source", ""))

        try:
            total_cal += float(r.get("calories", 0) or 0)
            total_protein += float(r.get("protein_g", 0) or 0)
            total_fat += float(r.get("fat_g", 0) or 0)
        except Exception:
            pass

        lines.append(f"{i}. {food} - {qty}{unit} - {cal} קל׳ | {protein}g חלבון | {fat}g שומן")

    source = source_label(src_values[0] if src_values else "")
    lines.append(f"סה״כ: {fmt_num(total_cal)} קל׳ | {fmt_num(total_protein)}g חלבון | {fmt_num(total_fat)}g שומן")
    lines.append(f"מקור: {source}")
    return "\n".join(lines)


def run_process_text(raw_text):
    before_rows = read_csv_rows()
    before_count = len(before_rows)

    env = os.environ.copy()

    proc = subprocess.run(
        [sys.executable, str(PROCESS_TEXT), raw_text],
        cwd=str(BASE_DIR),
        env=env,
        capture_output=True,
        text=True,
        timeout=90,
    )

    after_rows = read_csv_rows()
    new_rows = after_rows[before_count:]

    return proc.returncode, proc.stdout.strip(), proc.stderr.strip(), new_rows


def handle_update(token, update):
    update_id = update.get("update_id")
    msg = update.get("message") or {}
    chat = msg.get("chat") or {}
    chat_id = chat.get("id")
    text = (msg.get("text") or "").strip()

    if not update_id:
        return

    try:
        if not chat_id or not text:
            return

        rc, stdout, stderr, new_rows = run_process_text(text)

        if rc == 0:
            reply = build_success_reply(new_rows)
        else:
            reply = "לא הצלחתי לרשום את הדיווח"

        send_message(token, chat_id, reply)
        print(f"processed update_id={update_id} rc={rc} rows={len(new_rows)}", flush=True)

        if stdout:
            print(f"process_stdout={stdout[:300]}", flush=True)
        if stderr:
            print(f"process_stderr={stderr[:300]}", flush=True)

    finally:
        save_offset(int(update_id) + 1)


def run_once():
    token = read_token()
    updates = get_updates(token)
    for update in updates:
        handle_update(token, update)
    print(f"processed_updates={len(updates)}", flush=True)
    return 0


def run_loop():
    print("Rev002 Telegram bot loop started", flush=True)
    while True:
        try:
            run_once()
        except KeyboardInterrupt:
            print("stopped", flush=True)
            return 0
        except Exception as e:
            print(f"loop_error={e}", flush=True)
            time.sleep(5)
        time.sleep(2)


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--loop", action="store_true")
    args = parser.parse_args()

    if args.loop:
        return run_loop()
    return run_once()


if __name__ == "__main__":
    raise SystemExit(main())
