#!/usr/bin/env python3
import os, sys, json, time, uuid, csv, re
from datetime import datetime, timezone
BASE = os.path.expanduser('~/AI-Coach/health-watcher-rev002')
SCRIPTS = os.path.join(BASE, 'scripts')
DATA = os.path.join(BASE, 'data')
AGENT_PROMPT = os.path.join(SCRIPTS, 'agent_prompt.txt')
CSV_PATH = os.path.join(DATA, 'food_log.csv')

os.makedirs(SCRIPTS, exist_ok=True)
os.makedirs(DATA, exist_ok=True)

raw = ' '.join(sys.argv[1:]).strip()
if not raw:
    print('FAIL: no input text')
    sys.exit(2)

# build prompt
try:
    with open(AGENT_PROMPT, 'r', encoding='utf-8') as f:
        prompt_base = f.read()
except Exception:
    prompt_base = ''
prompt = prompt_base + '\nFood text: ' + raw + '\nReturn JSON only.'


# Try OpenClaw agent first (health_food_parser_rev002)# Try OpenClaw agent first (health_food_parser_rev002)
OPENCLAW_BIN = os.environ.get('OPENCLAW_BIN', '/home/roman/.nvm/versions/node/v24.15.0/bin/openclaw')
if os.path.exists(OPENCLAW_BIN):
    try:
        # call openclaw agent with safe single-line message built from prompt + raw
        oc_msg = prompt.strip() + '\n\nInput:\n' + raw.strip()
        cmd = [OPENCLAW_BIN, 'agent', '--agent', 'health_food_parser_rev002', '--message', oc_msg, '--json', '--timeout', '30']
        proc = __import__('subprocess').run(cmd, capture_output=True, text=True)
        if proc.returncode == 0 and proc.stdout:
            parsed_candidate = None
            try:
                parsed_candidate = extract_json(proc.stdout)
            except Exception:
                parsed_candidate = None
            if parsed_candidate:
                parsed = parsed_candidate
                parser_source = 'openclaw_agent'
                response_text = proc.stdout
    except Exception:
        pass
# try OpenAI via environment if available
agent_cmd = 'deterministic-fallback'
response_text = None
parser_source = 'deterministic_fallback'
openai_key = os.environ.get('OPENAI_API_KEY')
openai_model = os.environ.get('OPENAI_MODEL', 'gpt-5-nano')
if openai_key:
    try:
        import openai
        openai.api_key = openai_key
        agent_cmd = f'openai:{openai_model}'
        msg = prompt
        # prefer ChatCompletion
        try:
            resp = openai.ChatCompletion.create(model=openai_model, messages=[{'role':'user','content':msg}], temperature=0, max_tokens=400)
            response_text = resp['choices'][0]['message']['content']
            parser_source = 'openai'
        except Exception:
            try:
                resp = openai.Completion.create(model=openai_model, prompt=msg, max_tokens=400, temperature=0)
                response_text = resp['choices'][0]['text']
                parser_source = 'openai'
            except Exception:
                response_text = None
                parser_source = 'deterministic_fallback'
    except Exception:
        response_text = None
        parser_source = 'deterministic_fallback'
else:
    print('OPENAI_API_KEY missing; using deterministic fallback')

# fallback deterministic parser
if not response_text:
    agent_cmd = agent_cmd if response_text else 'deterministic-fallback'
    text = raw
    # Hebrew basic parsing for banana and egg
    items = []
    totals = {'calories':0,'protein_g':0,'fat_g':0}
    def add_item(name, qty, unit, cal, prot, fat, conf='medium'):
        items.append({'food_name':name,'quantity':qty,'unit':unit,'calories':cal,'protein_g':prot,'fat_g':fat,'confidence':conf})
        totals['calories'] += cal
        totals['protein_g'] += prot
        totals['fat_g'] += fat
    t = text
    # find bananas
    # patterns: 'בננה', optional number and unit
    m = re.search(r'בננה\s*(?:,|ו|-)?\s*(\d+(?:[\.,]\d+)?)?\s*(גרם|g)?', t)
    if m:
        num = m.group(1)
        unit = m.group(2) or 'g'
        if num:
            q = float(num.replace(',','.'))
            if unit in ('g','גרם','g'):
                factor = q/100.0
                cal = round(89 * factor)
                prot = round(1.1 * factor,1)
                fat = round(0.3 * factor,1)
                add_item('בננה', q, 'g', cal, prot, fat, 'high')
            else:
                add_item('בננה', float(num), unit, 89, 1.1, 0.3, 'medium')
        else:
            # no number -> assume 100g
            add_item('בננה', 100, 'g', 89, 1.1, 0.3, 'medium')
    # eggs
    # patterns: ביצה/ביצים
    m2 = re.search(r'(\d+)\s*ביצים|(?:ביצה|ביצים)(?:\s*(\d+))', t)
    if m2:
        num = m2.group(1) or m2.group(2)
        try:
            n = int(num)
        except Exception:
            n = 1
        # per egg approx
        cal = 72 * n
        prot = round(6.3 * n,1)
        fat = round(4.8 * n,1)
        add_item('ביצה', n, 'unit', cal, prot, fat, 'high')
    else:
        # also catch '2 ביצים' with 'ו' like 'ו-2 ביצים' or 'ו2 ביצים'
        m3 = re.search(r'ו[-–]?\s*(\d+)\s*ביצים', t)
        if m3:
            n = int(m3.group(1))
            cal = 72 * n
            prot = round(6.3 * n,1)
            fat = round(4.8 * n,1)
            add_item('ביצה', n, 'unit', cal, prot, fat, 'high')
    # if nothing parsed, return error
    if not items:
        out = {'status':'error','items':[], 'totals':{'calories':0,'protein_g':0,'fat_g':0}, 'error_reason':'no_parse'}
        response_text = json.dumps(out, ensure_ascii=False)
    else:
        out = {'status':'success','items':items,'totals':{'calories':totals['calories'],'protein_g':totals['protein_g'],'fat_g':totals['fat_g']},'error_reason':None}
        response_text = json.dumps(out, ensure_ascii=False)

# extract JSON safely (if agent returned extra text)
def extract_json(s):
    if not s:
        return None
    s = s.strip()
    # find first { and last }
    i = s.find('{')
    j = s.rfind('}')
    if i == -1 or j == -1 or j < i:
        return None
    try:
        return json.loads(s[i:j+1])
    except Exception:
        # try to fix common trailing commas
        try:
            fixed = re.sub(r',\s*}', '}', s[i:j+1])
            fixed = re.sub(r',\s*\]', ']', fixed)
            return json.loads(fixed)
        except Exception:
            return None

parsed = extract_json(response_text)
if parsed is None:
    print('FAIL: agent_json_not_found')
    print('Agent output:', response_text)
    sys.exit(2)

# validate
if 'status' not in parsed:
    print('FAIL: missing status')
    sys.exit(2)
if parsed.get('status') == 'success':
    items = parsed.get('items') or []
    if not items:
        print('FAIL: success but items empty')
        sys.exit(2)
    # validate numeric fields
    for it in items:
        for f in ('calories','protein_g','fat_g','quantity'):
            if f not in it:
                print(f'FAIL: missing {f} in item')
                sys.exit(2)
            try:
                float(it[f])
            except Exception:
                print(f'FAIL: {f} not numeric')
                sys.exit(2)
    if 'totals' not in parsed:
        print('FAIL: missing totals')
        sys.exit(2)
else:
    # error status -> require error_reason
    if not parsed.get('error_reason'):
        print('FAIL: error but no error_reason')
        sys.exit(2)

# if success, append CSV rows
rows_written = 0
if parsed.get('status') == 'success':
    eid = 'rev2-' + uuid.uuid4().hex
    ts = datetime.now(timezone.utc).astimezone().isoformat()
    header = ['timestamp','event_id','raw_text','food_name','quantity','unit','calories','protein_g','fat_g','confidence','status','parser_source']
    write_header = not os.path.exists(CSV_PATH)
    with open(CSV_PATH, 'a', newline='', encoding='utf-8') as csvf:
        writer = csv.writer(csvf)
        if write_header:
            writer.writerow(header)
        for it in parsed.get('items',[]):
            row = [ts, eid, raw, it.get('food_name'), it.get('quantity'), it.get('unit'), it.get('calories'), it.get('protein_g'), it.get('fat_g'), it.get('confidence'), parsed.get('status'), parser_source]
            writer.writerow(row)
            rows_written += 1
    print('OK')
    sys.exit(0)
else:
    print('FAIL: agent_error', parsed.get('error_reason'))
    sys.exit(2)
