"""Submission model functions — submissions, impressions, spam."""
import json
import hashlib
from datetime import datetime, timezone

from app.db import get_db
from app.crypto import (
    encrypt_value, try_decrypt, key_is_configured,
    encrypt_user_value, decrypt_user_value, try_decrypt_user_value,
    try_decrypt_user_submission, encrypt_user_submission,
    encrypt_entity, decrypt_entity, try_decrypt_entity,
    hash_value, is_encrypted,
)

# Import helpers
from app.helpers import (
    _decrypt_submission_fields, _encrypt_submission_field,
    _get_site_owner_password_hash, _is_encrypted_value,
    parse_user_agent, resolve_geo,
)

def add_submission(site_id, data, client_ip=None, user_agent=None, spam_flag=False, geo_city=None, geo_country=None, device_type=None, browser=None, os_name=None):
    """Add a submission without tier enforcement.

    Use `accept_submission` for the public API endpoint — it atomically
    checks the limit AND inserts the submission in one transaction.

    Submissions are encrypted with the site owner's password-derived key.
    """
    # Get site owner's password hash for user-scoped encryption
    password_hash = _get_site_owner_password_hash(site_id)

    conn = None
    try:
        conn = get_db()
        # Store dynamic fields in JSON (everything not captured by hardcoded columns)
        hardcoded_keys = {"name", "phone", "email", "equipment", "message", "token", "_fr_hp", "recaptcha_token"}
        dynamic_data = {k: v for k, v in data.items() if k not in hardcoded_keys}
        data_json = json.dumps(dynamic_data) if dynamic_data else None
    
        # Encrypt PII fields (user-scoped if we have password_hash)
        cust_name = _encrypt_submission_field(site_id, data.get("name", ""), password_hash)
        cust_phone = _encrypt_submission_field(site_id, data.get("phone", ""), password_hash)
        cust_email = _encrypt_submission_field(site_id, data.get("email", ""), password_hash)
        cust_equip = _encrypt_submission_field(site_id, data.get("equipment", ""), password_hash)
        cust_msg = _encrypt_submission_field(site_id, data.get("message", ""), password_hash)
        enc_data_json = encrypt_user_submission(password_hash, data_json) if password_hash and data_json else (encrypt_value(site_id, data_json) if data_json else None)
    
        cursor = conn.execute(
            """INSERT INTO submissions
               (site_id, customer_name, customer_phone, customer_email,
                customer_equipment, customer_message, data, client_ip, user_agent, spam_flag,
                geo_city, geo_country, device_type, browser, os)
               VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""",
            (
                site_id,
                cust_name,
                cust_phone,
                cust_email,
                cust_equip,
                cust_msg,
                enc_data_json,
                client_ip,
                user_agent,
                1 if spam_flag else 0,
                geo_city,
                geo_country,
                device_type,
                browser,
                os_name,
            ),
        )
        conn.commit()
        submission_id = cursor.lastrowid
        submission = conn.execute(
            "SELECT * FROM submissions WHERE id = ?", (submission_id,)
        ).fetchone()
    finally:
        if conn:
            conn.close()
    if submission:
        return _decrypt_submission_fields(site_id, dict(submission), password_hash)
    return None




def add_form_impression(site_id, client_ip=None, user_agent=None):
    """Record a form impression (view) with geo/device enrichment.

    Args:
        site_id: The site/form ID.
        client_ip: Client IP address (hashed for privacy).
        user_agent: Client user-agent string.

    Returns:
        dict with impression record or None on failure.
    """
    import hashlib

    conn = None
    try:
        conn = get_db()
        # Hash IP for privacy
        ip_hash = None
        if client_ip:
            ip_hash = hashlib.sha256(client_ip.encode()).hexdigest()

        # Enrich: GeoIP + User-Agent
        geo_city, geo_country = resolve_geo(client_ip)
        ua_info = parse_user_agent(user_agent)

        cursor = conn.execute(
            """INSERT INTO form_impressions
               (site_id, ip_hash, user_agent, geo_city, geo_country, device_type, browser, os)
               VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
            (
                site_id,
                ip_hash,
                user_agent,
                geo_city,
                geo_country,
                ua_info["device_type"],
                ua_info["browser"],
                ua_info["os"],
            ),
        )
        conn.commit()
        impression_id = cursor.lastrowid
        impression = conn.execute(
            "SELECT * FROM form_impressions WHERE id = ?", (impression_id,)
        ).fetchone()
        return dict(impression) if impression else None
    except Exception as e:
        print(f"[model] add_form_impression error: {e}")
        return None
    finally:
        if conn:
            conn.close()




def list_submissions(limit=50, site_filter=None, password_hash=None):
    """List submissions, optionally decrypted with user-scoped key.

    If password_hash is provided, uses user-scoped decryption.
    Otherwise returns raw encrypted data (admin view).
    """
    conn = None
    try:
        conn = get_db()
        if site_filter:
            rows = conn.execute(
                """SELECT s.*, si.name as site_name 
                   FROM submissions s JOIN sites si ON s.site_id = si.id 
                   WHERE si.id = ? ORDER BY s.submitted_at DESC LIMIT ?""",
                (site_filter, limit),
            ).fetchall()
        else:
            rows = conn.execute(
                """SELECT s.*, si.name as site_name 
                   FROM submissions s JOIN sites si ON s.site_id = si.id 
                   ORDER BY s.submitted_at DESC LIMIT ?""",
                (limit,),
            ).fetchall()
    finally:
        if conn:
            conn.close()
    results = []
    for r in rows:
        d = dict(r)
        results.append(_decrypt_submission_fields(d["site_id"], d, password_hash))
    return results




def list_submissions_raw(limit=50, site_filter=None):
    """List submissions without any decryption (admin view)."""
    return list_submissions(limit=limit, site_filter=site_filter, password_hash=None)




def get_submission(sub_id, password_hash=None):
    """Get a single submission, optionally decrypted with user-scoped key.

    If password_hash is provided, uses user-scoped decryption.
    Otherwise returns raw encrypted data (admin view).
    """
    conn = None
    try:
        conn = get_db()
        row = conn.execute(
            """SELECT s.*, si.name as site_name, si.owner_email 
               FROM submissions s JOIN sites si ON s.site_id = si.id 
               WHERE s.id = ?""",
            (sub_id,),
        ).fetchone()
    finally:
        if conn:
            conn.close()
    if row:
        d = dict(row)
        return _decrypt_submission_fields(d["site_id"], d, password_hash)
    return None




