"""
BlinkUI Transpiler — Store Analyzer

Detects global store() variables in the project
and generates a shared C struct accessible from all screens.

Python:
    cart_count = store(0)
    user_name  = store("")

Generated C (global_store.h):
    typedef struct {
        int   cart_count;
        char  user_name[256];
    } BKGlobalStore;

    extern BKGlobalStore bk_store;
"""

import ast
import os
import sys
sys.path.insert(0, os.path.dirname(__file__))

from type_inferrer import infer_c_type, infer_c_declaration, infer_c_initial
from parser import StateVar

def find_stores(project_dir: str) -> list:
    """Find all store() declarations in the project."""
    stores = []
    
    # check main.py and any top-level files
    for fname in ["main.py", "app.py", "stores.py", "state.py"]:
        fpath = os.path.join(project_dir, fname)
        if os.path.exists(fpath):
            stores.extend(_parse_stores(fpath))
    
    return stores

def _parse_stores(filepath: str) -> list:
    """Parse store() calls from a file."""
    stores = []
    try:
        with open(filepath) as f:
            source = f.read()
        tree = ast.parse(source)
        
        for node in ast.walk(tree):
            if isinstance(node, ast.Assign):
                if len(node.targets) == 1 and isinstance(node.targets[0], ast.Name):
                    name = node.targets[0].id
                    value = node.value
                    
                    # store(default)
                    if (isinstance(value, ast.Call) and
                        isinstance(value.func, ast.Name) and
                        value.func.id == "store" and
                        value.args):
                        
                        default = _eval_literal(value.args[0])
                        sv = StateVar(name=name, default=default)
                        sv.inferred_type = infer_c_type(default)
                        stores.append(sv)
    except Exception as e:
        print(f"  Store parse error in {filepath}: {e}")
    
    return stores

def _eval_literal(node):
    if isinstance(node, ast.Constant):
        return node.value
    if isinstance(node, ast.Dict):
        return {}
    if isinstance(node, ast.List):
        return []
    return None

def generate_global_store_h(stores: list, out_dir: str) -> str:
    """Generate global_store.h with shared state struct."""
    if not stores:
        # generate empty store
        header = '''// ── BlinkUI Global Store ──
// No global stores defined in this project
#ifndef BK_GLOBAL_STORE_H
#define BK_GLOBAL_STORE_H

typedef struct {
    int _empty;
} BKGlobalStore;

extern BKGlobalStore bk_store;

#endif
'''
    else:
        fields = []
        for sv in stores:
            fields.append(f"    {infer_c_declaration(sv)};")
        
        fields_str = "\n".join(fields)
        
        header = f'''// ── BlinkUI Global Store ──
// Generated by BlinkUI Transpiler
// DO NOT EDIT
#ifndef BK_GLOBAL_STORE_H
#define BK_GLOBAL_STORE_H

#include <string.h>

typedef struct {{
{fields_str}
}} BKGlobalStore;

// Global store instance — shared across all screens
extern BKGlobalStore bk_store;

#endif
'''
    
    out_path = os.path.join(out_dir, "global_store.h")
    with open(out_path, "w") as f:
        f.write(header)
    print(f"  ✅ Global store → {out_path}")
    return out_path

def generate_global_store_c(stores: list, out_dir: str) -> str:
    """Generate global_store.c with store initialization."""
    inits = []
    for sv in stores:
        if sv.inferred_type == "char":
            inits.append(f'    strncpy(bk_store.{sv.name}, {infer_c_initial(sv)}, 255);')
        else:
            inits.append(f'    bk_store.{sv.name} = {infer_c_initial(sv)};')
    
    inits_str = "\n".join(inits) if inits else "    // no stores"
    
    source = f'''// ── BlinkUI Global Store Implementation ──
#include "global_store.h"

// Global store instance
BKGlobalStore bk_store;

void bk_store_init(void) {{
{inits_str}
}}
'''
    
    out_path = os.path.join(out_dir, "global_store.c")
    with open(out_path, "w") as f:
        f.write(source)
    print(f"  ✅ Store init → {out_path}")
    return out_path


# ── Test ──
if __name__ == "__main__":
    import tempfile
    
    # create test stores.py
    test_stores = '''
from blinkui import store

cart_count = store(0)
user_name  = store("")
is_logged_in = store(False)
score = store(0.0)
'''
    
    with tempfile.TemporaryDirectory() as tmpdir:
        stores_file = os.path.join(tmpdir, "stores.py")
        with open(stores_file, "w") as f:
            f.write(test_stores)
        
        stores = find_stores(tmpdir)
        print(f"Found {len(stores)} stores:")
        for sv in stores:
            print(f"  {sv.name}: {sv.inferred_type} = {sv.default!r}")
        
        print("\nGenerating global_store.h:")
        h = generate_global_store_h(stores, tmpdir)
        print(open(h).read())
        
        print("Generating global_store.c:")
        c = generate_global_store_c(stores, tmpdir)
        print(open(c).read())
