import os
import json
import csv
from datetime import datetime, timedelta
from json.decoder import JSONDecodeError
from flask import Flask, render_template, request, jsonify, send_from_directory

# ----- Configuration Paths -----
LOG_CSV               = 'time_logs.csv'
MONTHLY_ACCOUNT       = 'account.json'
WEEKLY_ACCOUNT        = 'weekly_account.json'
MONTHLY_STATS_FOLDER  = 'monthly_stats'
WEEKLY_STATS_FOLDER   = 'weekly_stats'

# ----- Constants -----
SLOT_DURATION_MIN = 20
SLOTS_PER_DAY     = 12
SLOTS_PER_MONTH   = 240

app = Flask(__name__)


# ----- Helper: Monthly Account -----
def load_monthly_account():
    defaults = {
        'equity':           300.0,
        'working_capital':  300.0 / 3,
        'monthly_revenue':  0.0,
        'slot_count':       0
    }
    if os.path.exists(MONTHLY_ACCOUNT):
        try:
            return json.load(open(MONTHLY_ACCOUNT))
        except (JSONDecodeError, ValueError):
            pass
    with open(MONTHLY_ACCOUNT, 'w') as f:
        json.dump(defaults, f, indent=2)
    return defaults

def save_monthly_account(acct):
    with open(MONTHLY_ACCOUNT, 'w') as f:
        json.dump(acct, f, indent=2)


# ----- Helper: Weekly Account -----
def load_weekly_account():
    defaults = {
        'equity':           50.0,
        'working_capital':  50.0,
        'weekly_revenue':   0.0,
        'slot_count':       0,
        'start_equity':     50.0,
        'current_week':     datetime.now().isocalendar()[1]
    }
    if os.path.exists(WEEKLY_ACCOUNT):
        try:
            data = json.load(open(WEEKLY_ACCOUNT))
            for k, v in defaults.items():
                if k not in data:
                    data[k] = v
            return data
        except (JSONDecodeError, ValueError):
            pass
    with open(WEEKLY_ACCOUNT, 'w') as f:
        json.dump(defaults, f, indent=2)
    return defaults

def save_weekly_account(acct):
    with open(WEEKLY_ACCOUNT, 'w') as f:
        json.dump(acct, f, indent=2)


# ----- Logging Helper -----
def append_log(timestamp, slot_index):
    header = ['timestamp', 'slot_index']
    exists = os.path.exists(LOG_CSV)
    with open(LOG_CSV, 'a', newline='') as f:
        writer = csv.DictWriter(f, fieldnames=header)
        if not exists:
            writer.writeheader()
        writer.writerow({'timestamp': timestamp, 'slot_index': slot_index})


# ----- Weekly Rollover -----
def end_of_week_routine(weekly):
    year, week_num, _ = datetime.now().isocalendar()
    os.makedirs(WEEKLY_STATS_FOLDER, exist_ok=True)
    stats_path = os.path.join(
        WEEKLY_STATS_FOLDER, f'stats_{week_num}-{year}.json'
    )
    stats = {
        'start_equity':   weekly['start_equity'],
        'end_equity':     weekly['equity'],
        'weekly_revenue': weekly['weekly_revenue'],
        'slots_logged':   weekly['slot_count']
    }
    with open(stats_path, 'w') as f:
        json.dump(stats, f, indent=2)

    weekly['weekly_revenue'] = 0.0
    weekly['slot_count']     = 0
    weekly['start_equity']   = weekly['equity']
    weekly['current_week']   = week_num
    save_weekly_account(weekly)


# ----- Routes -----
@app.route('/')
def index():
    now = datetime.now()

    # --- Daily stats for chart & log button ---
    today_start   = now.replace(hour=0, minute=0, second=0, microsecond=0)
    slots_today   = 0
    last_log      = None
    hourly_counts = {h: 0 for h in range(24)}
    if os.path.exists(LOG_CSV):
        with open(LOG_CSV, 'r') as f:
            for row in csv.DictReader(f):
                ts = datetime.fromisoformat(row['timestamp'])
                if ts >= today_start:
                    slots_today += 1
                    last_log    = row['timestamp']
                    hourly_counts[ts.hour] += 1

    total_mins = slots_today * SLOT_DURATION_MIN
    percent    = min(int(total_mins / (SLOTS_PER_DAY * SLOT_DURATION_MIN) * 100), 100)
    goal_met   = (percent >= 100)
    hour_labels = [f"{h}:00" for h in range(24)]
    hours       = [hourly_counts[h] for h in range(24)]

    # --- Load accounts ---
    monthly = load_monthly_account()
    weekly  = load_weekly_account()

    # --- Monthly stats file check ---
    monthly_filename = f'stats_{now.year}_{now.month:02}.json'
    monthly_path     = os.path.join(MONTHLY_STATS_FOLDER, monthly_filename)
    monthly_stats_exists = os.path.exists(monthly_path)

    # --- Weekly stats file check ---
    year, week_num, _ = now.isocalendar()
    weekly_filename   = f'stats_{week_num}-{year}.json'
    weekly_path       = os.path.join(WEEKLY_STATS_FOLDER, weekly_filename)
    weekly_stats_exists = os.path.exists(weekly_path)

    return render_template(
        'index.html',
        # chart & controls
        last_log=last_log,
        total_mins=total_mins,
        percent=percent,
        goal_met=goal_met,
        hour_labels=hour_labels,
        hours=hours,
        # account data
        account_monthly=monthly,
        account_weekly=weekly,
        # stats file flags + filenames
        monthly_stats_exists=monthly_stats_exists,
        monthly_stats_file=monthly_filename,
        weekly_stats_exists=weekly_stats_exists,
        weekly_stats_file=weekly_filename
    )


@app.route('/log', methods=['POST'])
def log_time():
    """Log one 20‑min slot (up to 12/day), return updated totals."""
    now = datetime.now()
    today_start = now.replace(hour=0, minute=0, second=0, microsecond=0)

    # count how many slots have already been logged today
    slots_today = 0
    if os.path.exists(LOG_CSV):
        with open(LOG_CSV, newline='') as f:
            for row in csv.DictReader(f):
                ts = datetime.fromisoformat(row['timestamp'])
                if ts >= today_start:
                    slots_today += 1

    # new slot index (1..12)
    slot_index = min(slots_today + 1, SLOTS_PER_DAY)

    # append only if under the daily cap
    if slot_index > slots_today:
        append_log(now.isoformat(), slot_index)

    # 3) Update monthly account
    monthly = load_monthly_account()
    monthly['slot_count']      += 1
    revenue_m                  = 0.03 * monthly['working_capital']
    monthly['monthly_revenue'] += revenue_m
    save_monthly_account(monthly)

    # 4) Update weekly account
    weekly = load_weekly_account()
    weekly['slot_count'] += 1
    _, this_week, _ = now.isocalendar()
    if this_week != weekly.get('current_week'):
        end_of_week_routine(weekly)
    # Growth logic
    if weekly['equity'] < 4500:
        weekly['equity']          *= 1.03
        weekly['working_capital']  = weekly['equity']
        revenue_w = 0.0
    else:
        revenue_w = weekly['working_capital'] * 0.03
        weekly['equity'] += revenue_w
    weekly['weekly_revenue'] += revenue_w
    weekly['current_week']   = this_week
    save_weekly_account(weekly)

    # 5) Compute totals / percent
    total_mins = slot_index * SLOT_DURATION_MIN
    percent    = min(int(total_mins / (SLOTS_PER_DAY * SLOT_DURATION_MIN) * 100), 100)
    goal_met   = (percent >= 100)

    # 6) Return unified payload including sidebar data
    return jsonify({
        'slot_index': slot_index,
        'total_mins': total_mins,
        'percent':    percent,
        'goal_met':   goal_met,
        'monthly': {
            'equity':            round(monthly['equity'], 2),
            'working_capital':   round(monthly['working_capital'], 2),
            'monthly_revenue':   round(monthly['monthly_revenue'], 2)
        },
        'weekly': {
            'equity':            round(weekly['equity'], 2),
            'working_capital':   round(weekly['working_capital'], 2),
            'weekly_revenue':    round(weekly['weekly_revenue'], 2)
        },
        'timestamp': now.isoformat()
    })
   

# Download endpoints
@app.route('/monthly_stats/<path:filename>')
def download_monthly_stats(filename):
    return send_from_directory(MONTHLY_STATS_FOLDER, filename, as_attachment=True)

@app.route('/weekly_stats/<path:filename>')
def download_weekly_stats(filename):
    return send_from_directory(WEEKLY_STATS_FOLDER, filename, as_attachment=True)


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

