
from flask import Flask, render_template, request
import subprocess
import sys
import json
from flask import redirect
from urllib.request import urlopen
from pathlib import Path
from influxdb_client import InfluxDBClient
from datetime import datetime, timedelta

app = Flask(__name__)

BASE_DIR = Path(__file__).parent
CATEGORIES_FILE = BASE_DIR / "Kategorien.json"

config = {}

config_file = Path.home() / ".ing.conf"

if not config_file.exists():
    config_file = Path(__file__).parent / ".ing.conf"

with open(config_file, encoding="utf-8") as f:

    for line in f:

        line = line.strip()

        if not line or line.startswith("#"):
            continue

        if "=" not in line:
            continue

        key, value = line.split("=", 1)

        config[key] = value

IOBROKER_HOST = config["IOBROKER_HOST"]
IOBROKER_PORT = config["IOBROKER_PORT"]
IOBROKER_DP = config["IOBROKER_DP"]
INFLUX_URL = config.get("INFLUX_URL")
INFLUX_ORG = config.get("INFLUX_ORG")
INFLUX_BUCKET = config.get("INFLUX_BUCKET")
INFLUX_TOKEN = config.get("INFLUX_TOKEN")
BALANCE_YELLOW_DAY = int(
    config["BALANCE_YELLOW_DAY"]
)

BALANCE_YELLOW_LIMIT = float(
    config["BALANCE_YELLOW_LIMIT"]
)

BALANCE_RED_DAY = int(
    config["BALANCE_RED_DAY"]
)

BALANCE_RED_LIMIT = float(
    config["BALANCE_RED_LIMIT"]
)

def get_current_week_data():

    year, week, _ = datetime.now().isocalendar()

    summary_file = (
        BASE_DIR
        / "Transaktionen"
        / str(year)
        / "summary"
        / f"category_summary_{year}_KW{week:02d}.json"
    )

    transactions_file = (
        BASE_DIR
        / "Transaktionen"
        / str(year)
        / "categorized_json"
        / f"categorized_transactions_{year}_KW{week:02d}.json"
    )

    summary = None
    transactions = []
    unknown_transactions = []

    total_income = 0
    total_expenses = 0
    total_saldo = 0

    if summary_file.exists():

        with open(
            summary_file,
            encoding="utf-8"
        ) as f:

            summary = json.load(f)

        for values in summary.values():

            total_income += values["income"]
            total_expenses += values["expenses"]
            total_saldo += values["saldo"]

    if transactions_file.exists():

        with open(
            transactions_file,
            encoding="utf-8"
        ) as f:

            transactions = json.load(f)
        for transaction in transactions:

            if (
                    transaction.get("category")
                    == "Unbekannt"
            ):
                unknown_transactions.append(
                    transaction
                )

    return (
        year,
        week,
        summary,
        transactions,
        unknown_transactions,
        total_income,
        total_expenses,
        total_saldo
    )
def get_balance():

    try:

        url = (
            f"http://{IOBROKER_HOST}:{IOBROKER_PORT}"
            f"/getPlainValue/{IOBROKER_DP}"
        )

        value = (
            urlopen(url)
            .read()
            .decode("utf-8")
            .strip()
        )

        return float(value)

    except Exception as e:

        print(
            f"Kontostand konnte nicht gelesen werden: {e}"
        )

        return None
from datetime import datetime


def get_balance_color(balance):

    if balance is None:
        return "green"

    today = datetime.now().day

    if today >= BALANCE_RED_DAY:

        if balance < BALANCE_RED_LIMIT:
            return "red"

        if balance < BALANCE_YELLOW_LIMIT:
            return "orange"

        return "green"

    if today >= BALANCE_YELLOW_DAY:

        if balance < BALANCE_YELLOW_LIMIT:
            return "orange"

    return "green"


def get_balance_history(days=30):
    if not all([
        INFLUX_URL,
        INFLUX_ORG,
        INFLUX_BUCKET,
        INFLUX_TOKEN
    ]):
        return []
    client = InfluxDBClient(
        url=INFLUX_URL,
        token=INFLUX_TOKEN,
        org=INFLUX_ORG
    )

    query = f'''
    from(bucket: "{INFLUX_BUCKET}")
      |> range(start: -{days}d)
      |> filter(fn: (r) => r._measurement == "Kontostand")
      |> filter(fn: (r) => r._field == "value")
    '''

    result = client.query_api().query(query)

    history = []

    for table in result:
        for record in table.records:

            history.append({
                "date": record.get_time().strftime("%d.%m"),
                "value": round(record.get_value(), 2)
            })

    return history
@app.route("/")
def index():

    (
        year,
        week,
        summary,
        transactions,
        unknown_transactions,
        total_income,
        total_expenses,
        total_saldo
    ) = get_current_week_data()

    balance = get_balance()

    balance_color = get_balance_color(
        balance
    )

    balance_history = get_balance_history()

    return render_template(
        "index.html",
        year=year,
        week=week,
        summary=summary,
        transactions=transactions,
        unknown_transactions=unknown_transactions,
        total_income=total_income,
        total_expenses=total_expenses,
        total_saldo=total_saldo,
        balance=balance,
        balance_color=balance_color,
        balance_history=balance_history
    )
@app.route("/test-influx")
def test_influx():

    data = get_balance_history()

    return {
        "count": len(data),
        "first": data[0] if data else None,
        "last": data[-1] if data else None
    }


@app.route("/run/balance", methods=["POST"])
def run_balance():

    subprocess.run(
        [sys.executable, str(BASE_DIR / "balance.py")]
    )

    return redirect(
        "/maintenance?message=Kontostand erfolgreich aktualisiert"
    )

@app.route("/run/transactions", methods=["POST"])
def run_transactions():

    year = request.form.get("year", "").strip()
    week = request.form.get("week", "").strip()

    command = [
        sys.executable,
        str(BASE_DIR / "transactions.py")
    ]

    if year and week:
        command.extend([year, week])

    result = subprocess.run(
        command,
        capture_output=True,
        text=True
    )
    transaction_count = 0

    try:

        transactions_file = (
                BASE_DIR
                / "Transaktionen"
                / str(year)
                / "json"
                / f"transactions_{year}_KW{int(week):02d}.json"
        )

        if transactions_file.exists():
            with open(
                    transactions_file,
                    encoding="utf-8"
            ) as f:
                transaction_count = len(
                    json.load(f)
                )

    except Exception:
        pass
    return redirect(
        f"/maintenance?message={transaction_count} Transaktionen geladen"
    )


@app.route("/run/categorize", methods=["POST"])
def run_categorize():

    year = request.form.get("year", "").strip()
    week = request.form.get("week", "").strip()

    command = [
        sys.executable,
        str(BASE_DIR / "categorize_transactions.py")
    ]

    if year and week:
        command.extend([year, week])

    result = subprocess.run(
        command,
        capture_output=True,
        text=True
    )
    categorized_count = 0

    try:

        categorized_file = (
                BASE_DIR
                / "Transaktionen"
                / str(year)
                / "categorized_json"
                / f"categorized_transactions_{year}_KW{int(week):02d}.json"
        )

        if categorized_file.exists():
            with open(
                    categorized_file,
                    encoding="utf-8"
            ) as f:
                categorized_count = len(
                    json.load(f)
                )

    except Exception:
        pass
    return redirect(
        f"/maintenance?message={categorized_count} Buchungen kategorisiert"
    )
@app.route("/run/weekly_update", methods=["POST"])
def run_weekly_update():

    year = request.form.get("year", "").strip()
    week = request.form.get("week", "").strip()

    transaction_command = [
        sys.executable,
        str(BASE_DIR / "transactions.py")
    ]

    categorize_command = [
        sys.executable,
        str(BASE_DIR / "categorize_transactions.py")
    ]

    if year and week:

        transaction_command.extend(
            [year, week]
        )

        categorize_command.extend(
            [year, week]
        )

    subprocess.run(
        transaction_command
    )

    subprocess.run(
        categorize_command
    )

    transaction_count = 0

    try:

        transactions_file = (
                BASE_DIR
                / "Transaktionen"
                / str(year)
                / "json"
                / f"transactions_{year}_KW{int(week):02d}.json"
        )

        if transactions_file.exists():
            with open(
                    transactions_file,
                    encoding="utf-8"
            ) as f:
                transaction_count = len(
                    json.load(f)
                )

    except Exception:
        pass

    message = (
        f"{transaction_count} Transaktionen verarbeitet - "
        f"KW {week}/{year}"
    )

    return redirect(
        f"/maintenance?message={message}"
    )

@app.route("/categories")
def categories():

    with open(
        CATEGORIES_FILE,
        encoding="utf-8"
    ) as f:

        categories = json.load(f)
    #print(categories)
    return render_template(
        "categories.html",
        categories=categories
    )
@app.route("/categories/delete/<category>")
def delete_category(category):

    with open(
        CATEGORIES_FILE,
        encoding="utf-8"
    ) as f:

        categories = json.load(f)

    if category in categories:
        del categories[category]

    with open(
        CATEGORIES_FILE,
        "w",
        encoding="utf-8"
    ) as f:

        json.dump(
            categories,
            f,
            ensure_ascii=False,
            indent=2
        )

    return redirect("/categories")
@app.route(
    "/categories/add",
    methods=["POST"]
)
def add_category():

    category = request.form["category"].strip()

    with open(
        CATEGORIES_FILE,
        encoding="utf-8"
    ) as f:

        categories = json.load(f)

    if category not in categories:
        categories[category] = []

    with open(
        CATEGORIES_FILE,
        "w",
        encoding="utf-8"
    ) as f:

        json.dump(
            categories,
            f,
            ensure_ascii=False,
            indent=2
        )



    return redirect("/categories")
@app.route("/categories/edit/<category>")
def edit_category(category):

    with open(
        CATEGORIES_FILE,
        encoding="utf-8"
    ) as f:

        categories = json.load(f)

    if category not in categories:
        return redirect("/categories")

    return render_template(
        "edit_category.html",
        category=category,
        words=sorted(categories[category])
    )
@app.route(
    "/categories/add_word/<category>",
    methods=["POST"]
)
def add_word(category):

    word = request.form["word"].strip()

    with open(
        CATEGORIES_FILE,
        encoding="utf-8"
    ) as f:

        categories = json.load(f)

    if (
        category in categories
        and word
        and word not in categories[category]
    ):
        categories[category].append(word)

    with open(
        CATEGORIES_FILE,
        "w",
        encoding="utf-8"
    ) as f:

        json.dump(
            categories,
            f,
            ensure_ascii=False,
            indent=2
        )

    return redirect(
        f"/categories/edit/{category}"
    )
@app.route(
    "/categories/delete_word/<category>/<word>"
)
def delete_word(category, word):

    with open(
        CATEGORIES_FILE,
        encoding="utf-8"
    ) as f:

        categories = json.load(f)

    if (
        category in categories
        and word in categories[category]
    ):
        categories[category].remove(word)

    with open(
        CATEGORIES_FILE,
        "w",
        encoding="utf-8"
    ) as f:

        json.dump(
            categories,
            f,
            ensure_ascii=False,
            indent=2
        )

    return redirect(
        f"/categories/edit/{category}"
    )
@app.route("/maintenance")
def maintenance():

    year, week, _ = datetime.now().isocalendar()

    message = request.args.get(
        "message",
        ""
    )

    return render_template(
        "maintenance.html",
        year=year,
        week=week,
        message=message
    )
@app.route("/log")
def show_log():

    if sys.platform.startswith("win"):
        log_file = BASE_DIR / "logs" / "ing.log"
    else:
        log_file = Path.home() / "logs" / "ing.log"

    if not log_file.exists():

        return render_template(
            "log.html",
            log_content="Logdatei nicht gefunden."
        )

    with open(
            log_file,
            encoding="utf-8",
            errors="replace"
    ) as f:

        lines = f.readlines()

    log_content = "".join(lines[-200:])

    return render_template(
        "log.html",
        log_content=log_content
    )
if __name__ == "__main__":

    app.run(
        host="0.0.0.0",
        port=5000,
        debug=True
    )