#!/usr/bin/env python3
"""Finance Butler Dashboard — Flask App"""
from flask import Flask, render_template, jsonify, request
import sqlite3, os, re
from datetime import datetime, date, timedelta

app = Flask(__name__)
DB_PATH = os.path.expanduser("~/.hermes/profiles/finance-butler/finance.db")

def get_db():
    con = sqlite3.connect(DB_PATH)
    con.row_factory = sqlite3.Row
    return con

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/api/summary')
def api_summary():
    con = get_db()
    cur = con.cursor()
    today = date.today()
    this_month = today.strftime('%Y-%m')

    # 本月支出 (try current month, fallback to latest month with data)
    current_month = f'{today.year}-{today.month}'
    month_total = cur.execute(
        "SELECT SUM(amount) FROM expenses WHERE month=?", (current_month,)
    ).fetchone()[0] or 0
    # find latest month with data
    latest_month_row = cur.execute(
        "SELECT month FROM expenses WHERE month != '' ORDER BY month DESC LIMIT 1"
    ).fetchone()
    display_month = current_month if month_total > 0 else (latest_month_row[0] if latest_month_row else current_month)
    if display_month != current_month:
        month_total = cur.execute(
            "SELECT SUM(amount) FROM expenses WHERE month=?", (display_month,)
        ).fetchone()[0] or 0

    # 本月各分類
    by_parent = cur.execute("""
        SELECT parent, SUM(amount) as total
        FROM expenses WHERE month=?
        GROUP BY parent ORDER BY total DESC
    """, (display_month,)).fetchall()

    # 近6個月趨勢
    months_trend = cur.execute("""
        SELECT month, SUM(amount) as total
        FROM expenses
        WHERE date >= date('now', '-6 months')
        GROUP BY month ORDER BY month
    """).fetchall()

    # 持股損益
    holdings = cur.execute("SELECT * FROM holdings").fetchall()
    prices = {}
    for h in holdings:
        p = cur.execute("""
            SELECT close_price, change_amount, change_percent
            FROM stock_prices WHERE symbol=? ORDER BY date DESC LIMIT 1
        """, (h['symbol'],)).fetchone()
        prices[h['symbol']] = dict(p) if p else None

    con.close()

    holdings_data = []
    total_market_value = 0
    for h in holdings:
        p = prices.get(h['symbol'])
        market_val = (p['close_price'] * h['shares']) if p else None
        if market_val:
            total_market_value += market_val
        holdings_data.append({
            'symbol': h['symbol'],
            'name': h['name'],
            'shares': h['shares'],
            'total_cost': h['total_cost'],
            'close_price': p['close_price'] if p else None,
            'change_amount': p['change_amount'] if p else None,
            'change_percent': p['change_percent'] if p else None,
            'market_value': market_val,
        })

    return jsonify({
        'display_month': display_month,
        'month_total': month_total,
        'by_parent': [dict(r) for r in by_parent],
        'months_trend': [dict(r) for r in months_trend],
        'holdings': holdings_data,
        'total_market_value': total_market_value,
        'total_cost': 1952881,
    })

@app.route('/api/expenses')
def api_expenses():
    con = get_db()
    cur = con.cursor()
    month = request.args.get('month', '')
    today = date.today()
    if not month or month == 'current':
        # use latest month with data
        con2 = get_db()
        row = con2.execute("SELECT month FROM expenses WHERE month != '' ORDER BY month DESC LIMIT 1").fetchone()
        con2.close()
        month = row[0] if row else today.strftime('%Y-%-m')
    rows = cur.execute("""
        SELECT date, account, amount, category, parent, note
        FROM expenses WHERE month=?
        ORDER BY date DESC, id DESC
        LIMIT 200
    """, (month,)).fetchall()
    con.close()
    return jsonify([dict(r) for r in rows])

@app.route('/api/add_expense', methods=['POST'])
def api_add_expense():
    data = request.json
    today = date.today()
    con = get_db()
    cur = con.cursor()
    # Auto-detect parent from category
    parent = cur.execute(
        "SELECT parent FROM categories WHERE subcategory=?", (data.get('category',''),)
    ).fetchone()
    parent = parent[0] if parent else ''
    cur.execute("""
        INSERT INTO expenses (date, month, account, amount, category, parent, note, person)
        VALUES (?,?,?,?,?,?,?,?)
    """, (
        data.get('date', today.strftime('%Y/%m/%d')),
        data.get('month', today.strftime('%Y-%-m')),
        data.get('account', '現金'),
        data['amount'],
        data.get('category', ''),
        parent,
        data.get('note', ''),
        data.get('person', 'zami'),
    ))
    con.commit()
    con.close()
    return jsonify({'ok': True})

@app.route('/api/categories')
def api_categories():
    con = get_db()
    rows = con.execute("SELECT subcategory, parent, type FROM categories ORDER BY parent, subcategory").fetchall()
    con.close()
    return jsonify([dict(r) for r in rows])

@app.route('/api/parse_expense', methods=['POST'])
def api_parse_expense():
    text = (request.json or {}).get('text', '').strip()
    if not text:
        return jsonify({'error': 'empty text'}), 400

    result = parse_expense_text(text)
    return jsonify(result)


def parse_expense_text(text):
    today = date.today()

    # ── 1. Split-cost modifiers first (affect amount) ──────────────────────
    split = bool(re.search(r'各半|平分|AA制', text))

    # ── 2. Person patterns → note suffix ──────────────────────────────────
    note_suffix = ''
    m = re.search(r'跟([^\s，,。和和]{1,6}?)(?:一起|吃|買|去|喝|看|用|付|拆|各半|平分|AA|$)', text)
    if m:
        note_suffix = f'(與{m.group(1)})'
    m2 = re.search(r'(?:幫|代)([^\s，,。]{1,6}?)付', text)
    if m2:
        note_suffix = f'(代{m2.group(1)}付)'

    # ── 3. Amount extraction ───────────────────────────────────────────────
    # Match: NT$123, $123, 123元, 123塊, or bare number
    amt_match = re.search(
        r'(?:NT\$|＄|\$)\s*([0-9]+(?:\.[0-9]+)?)'
        r'|([0-9]+(?:\.[0-9]+)?)\s*(?:元|塊|NT\$|＄)',
        text)
    if not amt_match:
        amt_match = re.search(r'([0-9]+(?:\.[0-9]+)?)', text)
        raw_amount = float(amt_match.group(1)) if amt_match else None
    else:
        raw_amount = float(amt_match.group(1) or amt_match.group(2))

    amount = None
    if raw_amount is not None:
        amount = raw_amount / 2 if split else raw_amount

    # ── 4. Date extraction ─────────────────────────────────────────────────
    resolved_date = None
    weekday_map = {'一': 0, '二': 1, '三': 2, '四': 3, '五': 4, '六': 5, '日': 6, '天': 6}

    if re.search(r'今天|今日', text):
        resolved_date = today
    elif re.search(r'昨天|昨日', text):
        resolved_date = today - timedelta(days=1)
    elif re.search(r'前天', text):
        resolved_date = today - timedelta(days=2)
    else:
        m_week = re.search(r'(上週|上周|上星期|本週|本周|本星期)([一二三四五六日天])', text)
        if m_week:
            prefix, wd = m_week.group(1), m_week.group(2)
            target_wd = weekday_map.get(wd, 0)
            current_wd = today.weekday()
            if prefix.startswith('上'):
                days_back = (current_wd - target_wd) % 7 or 7
                days_back += 7 if days_back <= 0 else 0
            else:
                days_back = (current_wd - target_wd) % 7
            resolved_date = today - timedelta(days=days_back)

    if resolved_date is None:
        resolved_date = today

    date_str = resolved_date.strftime('%Y/%m/%d')
    month_str = f'{resolved_date.year}-{resolved_date.month}'

    # ── 5. Category matching ───────────────────────────────────────────────
    # Returns (subcategory, confidence_boost)
    RULES = [
        # 食
        (r'早餐',          '早餐',   0.95),
        (r'午餐',          '午餐',   0.95),
        (r'晚餐',          '晚餐',   0.95),
        (r'宵夜',          '宵夜',   0.95),
        (r'咖啡',          '飲料',   0.90),
        (r'飲料|手搖|珍奶|奶茶', '飲料', 0.90),
        (r'食材|買菜|菜市場', '食材', 0.90),
        (r'點心|零食|餅乾|蛋糕|麵包', '點心', 0.88),
        (r'外食|餐廳|吃飯|聚餐|火鍋|燒肉|壽司|拉麵|便當|麵|飯', '午餐', 0.80),
        # 行
        (r'加油',          '加油',   0.95),
        (r'計程車|Uber|優步|叫車', '計程車', 0.92),
        (r'捷運|公車|火車|高鐵|客運|車票|悠遊', '車票', 0.90),
        (r'停車|停車費',   '車錢',   0.88),
        (r'機票|飛機',     '機票',   0.92),
        (r'修車|保養',     '修車',   0.92),
        (r'租車',          '租車',   0.92),
        # 育
        (r'書(?!韋|店裡)',  '書',     0.90),
        (r'課程|上課|補習|家教', '學費', 0.88),
        (r'學費|學雜費',   '學費',   0.95),
        (r'文具|筆|筆記本', '文具',  0.88),
        (r'研討會|講座|演講', '研討會', 0.90),
        (r'興趣|才藝',     '興趣',   0.85),
        # 樂
        (r'電影|Netflix|Disney|迪士尼|串流|影集|劇', '電影', 0.85),
        (r'遊戲|玩具',     '玩具',   0.85),
        (r'門票|展覽|表演|演唱會|音樂會(?!器)', '門票', 0.88),
        (r'住宿|旅館|飯店|民宿', '住宿', 0.90),
        # 醫
        (r'藥局|藥房|藥品|買藥|吃藥|藥$', '藥',    0.92),
        (r'維他命|保健品|益生菌|魚油|營養', '營養食品', 0.90),
        (r'看病|診所|醫院|掛號|醫生|牙醫', '看病',  0.92),
        # 生活
        (r'全聯|家樂福|大潤發|超市|量販|好市多|costco', '日用品', 0.88),
        (r'日用品|衛生紙|洗髮|沐浴|清潔', '日用品', 0.88),
        (r'網路費|網路|WiFi|寬頻',  '網路',   0.88),
        (r'Spotify|Apple Music|訂閱', '網路',  0.80),
        (r'傢俱|家具|桌椅|床|沙發', '傢俱',   0.90),
        (r'電器|家電|冰箱|洗衣機|冷氣', '電器', 0.88),
        # 住
        (r'房租',          '房租',   0.95),
        (r'水電|電費|水費|瓦斯', '水電', 0.92),
        (r'電話費|電信|手機費|通信', '通信', 0.90),
        # 衣
        (r'置裝|衣服|買衣|服飾|鞋子', '置裝', 0.88),
        (r'美容|美甲|美睫|SPA|護膚|按摩', '美容', 0.88),
        (r'理髮|剪髮|燙髮|染髮|美髮', '理髮', 0.90),
        # 禮
        (r'禮物|送禮',     '禮物',   0.88),
        (r'捐款|公益',     '捐款',   0.90),
        # 音樂
        (r'音樂會|演奏|表演',  '表演', 0.85),
        (r'樂器|吉他|鋼琴|小提琴', '樂器', 0.90),
        # 寵物
        (r'寵物|狗|貓|倉鼠|兔子',  '寵物食品', 0.80),
        (r'寵物看病|動物醫院|獸醫', '寵物看病', 0.92),
    ]

    category = ''
    confidence = 0.5

    for pattern, cat, conf in RULES:
        if re.search(pattern, text, re.IGNORECASE):
            category = cat
            confidence = conf
            break

    # ── 6. Build note ─────────────────────────────────────────────────────
    # Extract descriptive note: remove amount, date words, category words
    note_text = text
    note_text = re.sub(r'(?:NT\$|＄|\$)\s*[0-9]+(?:\.[0-9]+)?', '', note_text)
    note_text = re.sub(r'[0-9]+(?:\.[0-9]+)?\s*(?:元|塊)', '', note_text)
    note_text = re.sub(r'[0-9]+', '', note_text)
    note_text = re.sub(r'今天|今日|昨天|昨日|前天|上週|上周|本週|本周|上星期|本星期|這個月|本月', '', note_text)
    note_text = re.sub(r'[一二三四五六日天]', '', note_text)
    note_text = re.sub(r'各半|平分|AA制|跟.{1,6}?(一起|吃|買|去|喝|看|用|付|拆|各半|平分|AA|$)', '', note_text)
    note_text = re.sub(r'(?:幫|代).{1,6}?付', '', note_text)
    note_text = re.sub(r'[，,。！!？?、\s]+', ' ', note_text).strip()

    if note_text and note_suffix:
        note = note_text + note_suffix
    elif note_suffix:
        note = note_suffix
    else:
        note = note_text

    if split and note and '各半' not in note and '平分' not in note:
        note = note.rstrip(')') + ('各半)' if note.endswith(')') else '(各半)')

    return {
        'amount': amount,
        'category': category,
        'note': note,
        'date': date_str,
        'month': month_str,
        'account': '現金',
        'confidence': round(confidence, 2),
    }


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=38423, debug=False)
