#!/usr/bin/env bash
set -euo pipefail

REPO_DIR="/home/agent/projects/CryptoTradingBot/Crypto_Agent"
RUNTIME_DIR="/home/agent/.local/state/CryptoTradingBot/copy_research"
START_DAY="$(date -u +%F)"
RUN_DIR="$RUNTIME_DIR/reports/observation_runs"
RUN_ID="${START_DAY}_7d"
LOG_FILE="$RUN_DIR/${RUN_ID}.log"
STATUS_FILE="$RUN_DIR/${RUN_ID}_status.json"
SUMMARY_FILE="$RUN_DIR/${RUN_ID}_summary.md"
INTERVAL_SECONDS="${CTB_OBSERVATION_INTERVAL_SECONDS:-7200}"
EXPECTED_CYCLES="${CTB_OBSERVATION_EXPECTED_CYCLES:-84}"
START_ISO="$(date -u --iso-8601=seconds)"

mkdir -p "$RUN_DIR"
cd "$REPO_DIR"

safety_check() {
  PYTHONPATH=. python3 - <<'PY'
from src.ctb_copy.read_only_guard import DEFAULT_READ_ONLY_GUARD
DEFAULT_READ_ONLY_GUARD.assert_safe()
print(DEFAULT_READ_ONLY_GUARD.as_dict())
PY
  local forbidden_re
  forbidden_re="create_""order|market_""open|set_""leverage|vault""Deposit|exchange\\.order|Account\\.from_""key|HL_AGENT_""PRIVATE_KEY|HL_API_""PRIVATE_KEY"
  if grep -RInE "$forbidden_re" src/ctb_copy >/tmp/ctb_copy_observation_7d_safety_hits.txt; then
    echo "SAFETY VIOLATION: execution-capable pattern found in src/ctb_copy"
    cat /tmp/ctb_copy_observation_7d_safety_hits.txt
    return 1
  fi
}

write_status() {
  local cycle="$1"
  local run_status="$2"
  local last_cycle_at
  last_cycle_at="$(date -u --iso-8601=seconds)"
  START_ISO="$START_ISO" START_DAY="$START_DAY" LAST_CYCLE_AT="$last_cycle_at" CYCLES_COMPLETED="$cycle" EXPECTED_CYCLES="$EXPECTED_CYCLES" RUN_STATUS="$run_status" RUNTIME_DIR="$RUNTIME_DIR" STATUS_FILE="$STATUS_FILE" SUMMARY_FILE="$SUMMARY_FILE" PYTHONPATH=. python3 - <<'PY'
import json, os
from pathlib import Path
from datetime import datetime, timezone
from collections import Counter

runtime = Path(os.environ['RUNTIME_DIR'])
start_day = os.environ['START_DAY']
status_file = Path(os.environ['STATUS_FILE'])
summary_file = Path(os.environ['SUMMARY_FILE'])
cycles = int(os.environ['CYCLES_COMPLETED'])
expected = int(os.environ['EXPECTED_CYCLES'])

watchlist_path = runtime / 'state' / 'watchlist.json'
watchlist = json.loads(watchlist_path.read_text()) if watchlist_path.exists() else {'wallets': []}
enabled_wallets = [w for w in watchlist.get('wallets', []) if w.get('enabled', True)]

snapshot_counts = Counter()
total_snapshots = 0
for f in sorted((runtime / 'snapshots' / 'wallets').glob('*/snapshots.jsonl')):
    day = f.parent.name
    if day < start_day:
        continue
    for line in f.read_text(encoding='utf-8').splitlines():
        if not line.strip():
            continue
        try:
            row = json.loads(line)
        except Exception:
            continue
        label = str(row.get('label') or row.get('wallet_address') or row.get('leader_id') or 'unknown')
        snapshot_counts[label] += 1
        total_snapshots += 1

decision_counts = Counter()
reason_counts = Counter()
symbols = set()
leaders = set()
for f in sorted((runtime / 'shadow').glob('*/position_decisions.jsonl')):
    day = f.parent.name
    if day < start_day:
        continue
    for line in f.read_text(encoding='utf-8').splitlines():
        if not line.strip():
            continue
        try:
            row = json.loads(line)
        except Exception:
            continue
        decision_counts[str(row.get('decision', 'unknown'))] += 1
        if row.get('symbol'):
            symbols.add(str(row['symbol']))
        if row.get('leader_id'):
            leaders.add(str(row['leader_id']))
        for reason in row.get('reason_codes') or []:
            reason_counts[str(reason)] += 1

latest_collector = {}
collector_files = sorted((runtime / 'reports' / 'collector_results').glob('*.json'))
for f in reversed(collector_files):
    if f.stem >= start_day:
        try:
            latest_collector = json.loads(f.read_text())
            break
        except Exception:
            pass

status = {
    'run_id': f'{start_day}_7d',
    'run_started_at': os.environ['START_ISO'],
    'last_cycle_at': os.environ['LAST_CYCLE_AT'],
    'run_status': os.environ['RUN_STATUS'],
    'cycles_completed': cycles,
    'expected_cycles_total': expected,
    'progress_pct': round(cycles / expected * 100, 1) if expected else 0,
    'enabled_wallets_count': len(enabled_wallets),
    'wallet_labels': [str(w.get('label','')) for w in enabled_wallets],
    'wallet_snapshot_count_total_since_start_day': total_snapshots,
    'snapshot_count_by_wallet_since_start_day': dict(snapshot_counts),
    'shadow_decisions_count_since_start_day': sum(decision_counts.values()),
    'allowed_count_since_start_day': decision_counts.get('allowed', 0),
    'blocked_count_since_start_day': decision_counts.get('blocked', 0),
    'ignored_count_since_start_day': decision_counts.get('ignored', 0),
    'top_reasons_since_start_day': dict(reason_counts.most_common(10)),
    'symbols_observed_since_start_day': sorted(symbols),
    'leaders_observed_since_start_day': sorted(leaders),
    'collector_status_latest': latest_collector.get('status', 'unknown'),
    'data_quality_latest': latest_collector.get('data_quality', ['unknown']),
    'partial_errors_latest': latest_collector.get('partial_errors', []),
    'safety_status': 'read_only_ok',
    'read_only_guard': {'read_only': True, 'live_orders': False, 'vault_deposits': False, 'wallet_execution': False, 'signing_enabled': False},
    'status_file': str(status_file),
    'summary_file': str(summary_file),
}
status_file.write_text(json.dumps(status, indent=2, sort_keys=True) + '\n', encoding='utf-8')

summary = f"""# Copy Observation 7d Summary – {start_day}

## Status
- run_status: {status['run_status']}
- run_started_at: {status['run_started_at']}
- last_cycle_at: {status['last_cycle_at']}
- cycles_completed: {cycles}
- expected_cycles_total: {expected}
- progress_pct: {status['progress_pct']}

## Watchlist
- enabled_wallets_count: {status['enabled_wallets_count']}
- wallet_labels: {status['wallet_labels']}

## Snapshots und Shadow Decisions seit Starttag
- wallet_snapshot_count_total_since_start_day: {total_snapshots}
- shadow_decisions_count_since_start_day: {sum(decision_counts.values())}
- allowed_count_since_start_day: {decision_counts.get('allowed', 0)}
- blocked_count_since_start_day: {decision_counts.get('blocked', 0)}
- ignored_count_since_start_day: {decision_counts.get('ignored', 0)}
- top_reasons_since_start_day: {dict(reason_counts.most_common(10))}
- symbols_observed_since_start_day: {sorted(symbols)}

## API und Safety
- collector_status_latest: {status['collector_status_latest']}
- data_quality_latest: {status['data_quality_latest']}
- partial_errors_latest: {status['partial_errors_latest']}
- safety_status: read_only_ok

## Safety
Keine Live-Entscheidung. Keine Live-Copy. Keine Vault-Deposits. Keine Wallet/API-Wallet-Execution. Keine Orders. Kein Signing.
"""
summary_file.write_text(summary, encoding='utf-8')
print(json.dumps(status, sort_keys=True))
PY
}

trap 'echo "aborted_at=$(date -u --iso-8601=seconds)" >> "$LOG_FILE"; write_status "${cycle:-0}" "aborted" >> "$LOG_FILE" 2>&1 || true; echo "7d copy observation aborted; status=$STATUS_FILE summary=$SUMMARY_FILE"' ERR

{
  echo "READ ONLY 7D COPY OBSERVATION RUN"
  echo "NO ORDERS / NO SIGNING / NO VAULT DEPOSITS / NO WALLET EXECUTION"
  echo "start=$START_ISO expected_cycles=$EXPECTED_CYCLES interval_seconds=$INTERVAL_SECONDS"
  safety_check
  write_status 0 started
} >> "$LOG_FILE" 2>&1

cycle=1
while [ "$cycle" -le "$EXPECTED_CYCLES" ]; do
  {
    echo "cycle=$cycle started_at=$(date -u --iso-8601=seconds)"
    safety_check
    PYTHONPATH=. python3 -m src.ctb_copy.run_collector_once
    PYTHONPATH=. python3 -m src.ctb_copy.run_shadow_once
    PYTHONPATH=. python3 -m src.ctb_copy.reports.daily_copy_report
    write_status "$cycle" running
    echo "cycle=$cycle completed_at=$(date -u --iso-8601=seconds)"
  } >> "$LOG_FILE" 2>&1
  if [ "$cycle" -ge "$EXPECTED_CYCLES" ]; then
    break
  fi
  cycle="$((cycle + 1))"
  sleep "$INTERVAL_SECONDS"
done

write_status "$EXPECTED_CYCLES" completed >> "$LOG_FILE" 2>&1
completed_at="$(date -u --iso-8601=seconds)"
echo "completed_at=$completed_at" >> "$LOG_FILE"
echo "Copy Observation 7d completed. Summary: $SUMMARY_FILE Status: $STATUS_FILE Log: $LOG_FILE"
