#!/usr/bin/env python3
"""
Ichimoku Cloud Chart Generator for IDX stocks.
Uses REAL OHLC data parsed from Yahoo Finance web pages.

Usage (from execute_code):
  1. Extract data via web_extract from https://finance.yahoo.com/quote/{TICKER}.JK/history/
  2. Pass CSV string to generate_chart() or call from CLI:
     python3.12 /path/to/ichimoku_chart.py SMSM "/tmp/smsm_ohlc.csv"

CSV format: Date,Open,High,Low,Close (header required)

IMPORTANT: Use python3.12 (system python), NOT the hermes-agent venv python.
  The venv lacks matplotlib. The script will fail silently or error if run with venv python.
"""

import sys
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
from io import StringIO
import csv

CLOUD = 26  # standard Ichimoku offset


def parse_csv(csv_text: str):
    """Parse OHLC CSV string into lists of datetime, opens, highs, lows, closes."""
    dates, opens, highs, lows, closes = [], [], [], [], []
    reader = csv.DictReader(StringIO(csv_text.strip()))
    for row in reader:
        try:
            dates.append(datetime.strptime(row['Date'].strip(), '%Y-%m-%d'))
            highs.append(float(row['High']))
            lows.append(float(row['Low']))
            closes.append(float(row['Close']))
            opens.append(float(row['Open']))
        except (KeyError, ValueError):
            continue
    return dates, opens, highs, lows, closes


def roll_hl(highs, lows, i, period):
    s = max(0, i - period + 1)
    return max(highs[s:i+1]), min(lows[s:i+1])


def calculate_ichimoku(highs, lows, closes):
    """Return tenkan, kijun, senkou_a, senkou_b, chikou lists."""
    n = len(closes)
    tenkan, kijun = [], []
    for i in range(n):
        h9, l9 = roll_hl(highs, lows, i, 9)
        h26, l26 = roll_hl(highs, lows, i, 26)
        tenkan.append((h9 + l9) / 2)
        kijun.append((h26 + l26) / 2)

    senkou_a = [None] * CLOUD
    for i in range(CLOUD, n):
        senkou_a.append((tenkan[i] + kijun[i]) / 2)

    senkou_b = [None] * CLOUD
    for i in range(CLOUD, n):
        h52, l52 = roll_hl(highs, lows, i, 52)
        senkou_b.append((h52 + l52) / 2)

    chikou = [None] * CLOUD + [closes[i - CLOUD] for i in range(CLOUD, n)]
    return tenkan, kijun, senkou_a, senkou_b, chikou


def signal_board(closes, tenkan, kijun, senkou_a, senkou_b, chikou, dates):
    """Print Ichimoku signal analysis."""
    n = len(closes)
    last = n - 1

    tk = tenkan[last] > kijun[last]
    price_cloud = closes[last] > max(senkou_a[last], senkou_b[last])
    cloud_bull = senkou_a[last] > senkou_b[last]
    chikou_sig = chikou[last] is not None and chikou[last] > closes[last]

    # Find most recent TK cross
    tk_cross_date = None
    for i in range(n - 2, -1, -1):
        if (tenkan[i] < kijun[i] and tenkan[i+1] >= kijun[i+1]):
            tk_cross_date = dates[i+1].date()
            break

    print(f"\n{'='*50}")
    print(f"  ICHIMOKU ANALYSIS — {dates[-1].date()}")
    print(f"{'='*50}")
    print(f"  Harga Penutupan     : Rp {closes[-1]:.0f}")
    print(f"  Tenkan-sen (9)      : Rp {tenkan[-1]:.2f}")
    print(f"  Kijun-sen (26)      : Rp {kijun[-1]:.2f}")
    print(f"  Senkou A (26 fwd)   : Rp {senkou_a[-1]:.2f}")
    print(f"  Senkou B (52 fwd)   : Rp {senkou_b[-1]:.2f}")
    if chikou[-1] is not None:
        print(f"  Chikou (26 back)    : Rp {chikou[-1]:.0f}  (close 26 days ago: {dates[-27].date() if n > 26 else 'N/A'})")
    print()
    print(f"  === SIGNAL BOARD ===")
    print(f"  Tenkan > Kijun     : {'✅ BULLISH' if tk else '❌ BEARISH'}")
    if tk_cross_date:
        print(f"  TK Cross Date       : {tk_cross_date}")
    print(f"  Harga > Cloud       : {'✅ ABOVE CLOUD' if price_cloud else '❌ BELOW CLOUD'}")
    print(f"  Cloud Color         : {'🟢 GREEN (A>B)' if cloud_bull else '🔴 RED (B>A)'}")
    print(f"  Chikou > Harga(26) : {'✅ BULLISH' if chikou_sig else '❌ BEARISH'}")
    print()
    score = sum([tk, price_cloud, cloud_bull, chikou_sig])
    print(f"  BULLISH SIGNALS     : {score}/4")
    verdict = "🟢 TREND BULLISH" if score >= 3 else "🔴 TREND BEARISH" if score <= 1 else "🟡 NETRAL / TRANSITIONING"
    print(f"  VERDICT             : {verdict}")

    return tk, kijun, senkou_a, senkou_b, chikou, tk_cross_date


def generate_chart(dates, opens, highs, lows, closes, ticker="STOCK", save_path=None):
    """Main chart generation function."""
    n = len(dates)
    tenkan, kijun, senkou_a, senkou_b, chikou = calculate_ichimoku(highs, lows, closes)

    # Signal summary (print only, don't block chart)
    signal_board(closes, tenkan, kijun, senkou_a, senkou_b, chikou, dates)

    # Plot last 120 candles for readability
    start = max(0, n - 120)
    pdates = dates[start:]
    pcloses = closes[start:]
    ptenkan = tenkan[start:]
    pkijun = kijun[start:]
    psa = senkou_a[start:]
    psb = senkou_b[start:]

    fig, ax = plt.subplots(figsize=(20, 10))
    fig.patch.set_facecolor('#0d1117')
    ax.set_facecolor('#0d1117')

    x = np.arange(len(pdates))

    # Cloud fills
    ca = np.array([v if v is not None else np.nan for v in psa], dtype=float)
    cb = np.array([v if v is not None else np.nan for v in psb], dtype=float)
    ax.fill_between(x, ca, cb, where=(ca >= cb), color='#00b894', alpha=0.35, label='Cloud Bullish (A≥B)')
    ax.fill_between(x, ca, cb, where=(cb > ca), color='#e17055', alpha=0.35, label='Cloud Bearish (B>A)')

    # Senkou lines
    ax.plot(x, ca, color='#00b894', linewidth=1.2, label='Senkou A')
    ax.plot(x, cb, color='#e17055', linewidth=1.2, label='Senkou B')

    # Price close line
    ax.plot(x, pcloses, color='#dfe6e9', linewidth=1.5, label='Close')

    # High/low range (light)
    phighs = highs[start:]
    plow = lows[start:]
    ax.plot(x, phighs, color='#74b9ff', linewidth=0.4, alpha=0.35)
    ax.plot(x, plow, color='#fdcb6e', linewidth=0.4, alpha=0.35)

    # Tenkan & Kijun
    ax.plot(x, ptenkan, color='#0984e3', linewidth=1.5, label='Tenkan-sen (9)')
    ax.plot(x, pkijun, color='#d63031', linewidth=1.5, label='Kijun-sen (26)')

    # Chikou (shifted 26 periods forward on chart for visual alignment)
    chikou_vis = []
    for i in range(len(pdates)):
        idx = i + CLOUD
        if idx < n:
            chikou_vis.append(closes[idx])
        else:
            chikou_vis.append(np.nan)
    ax.plot(x, chikou_vis, color='#a29bfe', linewidth=1.3, linestyle='--', label='Chikou (26)')

    # Current price label
    ax.axhline(y=pcloses[-1], color='#dfe6e9', linestyle=':', alpha=0.4, linewidth=0.8)
    ax.text(len(x) - 1, pcloses[-1] + (max(phighs) - min(plow)) * 0.015,
            f'{pcloses[-1]:.0f}', color='#dfe6e9', fontsize=9, ha='right', va='bottom')

    # X-axis
    ax.set_xlim(0, len(pdates) - 1)
    tick_pos = list(range(0, len(pdates), 10))
    tick_labels = [pdates[i].strftime('%d/%m') for i in tick_pos]
    ax.set_xticks(tick_pos)
    ax.set_xticklabels(tick_labels, color='#636e72', fontsize=8)
    ax.tick_params(colors='#636e72')
    ax.grid(True, alpha=0.08, color='#636e72')
    for spine in ax.spines.values():
        spine.set_edgecolor('#2d3436')

    ax.set_title(f'{ticker} — Ichimoku Cloud Chart ({dates[-1].date()})',
                 color='#dfe6e9', fontsize=14, fontweight='bold', pad=10)
    ax.set_ylabel('Harga (IDR)', color='#dfe6e9', fontsize=10)
    ax.legend(loc='upper left', fontsize=9, framealpha=0.3,
              facecolor='#161b22', edgecolor='#2d3436', labelcolor='#dfe6e9')

    plt.tight_layout()

    if save_path is None:
        save_path = f'/tmp/{ticker}_ichimoku.png'
    plt.savefig(save_path, dpi=150, bbox_inches='tight', facecolor='#0d1117')
    plt.close()
    print(f"\nChart saved: {save_path}")
    return save_path


if __name__ == '__main__':
    # CLI usage: python3.12 ichimoku_chart.py <ticker> <csv_file_path>
    if len(sys.argv) < 3:
        print("Usage: python3 ichimoku_chart.py <ticker> <csv_file>")
        print("  csv_file: path to CSV with Date,Open,High,Low,Close columns")
        print("Example: python3 ichimoku_chart.py SMSM /tmp/smsm_data.csv")
        sys.exit(1)

    ticker = sys.argv[1]
    csv_path = sys.argv[2]

    with open(csv_path, 'r') as f:
        csv_text = f.read()

    dates, opens, highs, lows, closes = parse_csv(csv_text)
    if not dates:
        print("ERROR: No valid data parsed from CSV. Check column names (Date,Open,High,Low,Close).")
        sys.exit(1)

    print(f"Parsed {len(dates)} candles: {dates[0].date()} → {dates[-1].date()}")
    save_path = f'/tmp/{ticker}_ichimoku.png'
    generate_chart(dates, opens, highs, lows, closes, ticker=ticker, save_path=save_path)
