from textual.app import ComposeResult
from textual.screen import ModalScreen
from textual.containers import Container, Horizontal, Vertical, ScrollableContainer
from textual.widgets import Static, Button, Input, Label, ListView, ListItem, Rule, OptionList, Footer
from textual import on
from textual.message import Message
from typing import Dict, Any, List, Optional
import os
import json

from pathlib import Path
from SYS.config import load_config, save_config
from Store.registry import _discover_store_classes, _required_keys_for

class ConfigModal(ModalScreen):
    """A modal for editing the configuration."""

    CSS = """
    ConfigModal {
        align: center middle;
        background: $boost;
    }

    #config-container {
        width: 90%;
        height: 90%;
        background: $panel;
        border: thick $primary;
        padding: 1;
    }

    .section-title {
        background: $accent;
        color: $text;
        padding: 0 1;
        margin-bottom: 1;
        text-align: center;
        text-style: bold;
        height: 3;
        content-align: center middle;
    }

    #config-sidebar {
        width: 25%;
        border-right: solid $surface;
    }

    #config-content {
        width: 75%;
        padding: 1;
    }

    .config-field {
        margin-bottom: 1;
        height: auto;
    }

    .config-label {
        width: 100%;
        text-style: bold;
        color: $accent;
    }

    .config-input {
        width: 100%;
    }

    #config-actions {
        height: 3;
        align: right middle;
    }

    .item-row {
        height: 3;
        margin-bottom: 1;
        padding: 0 1;
        border: solid $surface;
    }

    .item-label {
        width: 1fr;
        content-align: left middle;
    }

    Button {
        margin: 0 1;
    }
    """

    def __init__(self) -> None:
        super().__init__()
        # Load config from the workspace root (parent of SYS)
        workspace_root = Path(__file__).resolve().parent.parent.parent
        self.config_data = load_config(config_dir=workspace_root)
        self.current_category = "globals"
        self.editing_item_type = None  # 'store' or 'provider'
        self.editing_item_name = None
        self.workspace_root = workspace_root

    def compose(self) -> ComposeResult:
        with Container(id="config-container"):
            yield Static("CONFIGURATION EDITOR", classes="section-title")
            with Horizontal():
                with Vertical(id="config-sidebar"):
                    yield Label("Categories", classes="config-label")
                    with ListView(id="category-list"):
                        yield ListItem(Label("Global Settings"), id="cat-globals")
                        yield ListItem(Label("Stores"), id="cat-stores")
                        yield ListItem(Label("Providers"), id="cat-providers")
                
                with Vertical(id="config-content"):
                    yield ScrollableContainer(id="fields-container")
                    with Horizontal(id="config-actions"):
                        yield Button("Save", variant="success", id="save-btn")
                        yield Button("Add Store", variant="primary", id="add-store-btn")
                        yield Button("Back", id="back-btn")
                        yield Button("Close", variant="error", id="cancel-btn")

    def on_mount(self) -> None:
        self.query_one("#add-store-btn", Button).display = False
        self.query_one("#back-btn", Button).display = False
        self.refresh_view()

    def refresh_view(self) -> None:
        container = self.query_one("#fields-container", ScrollableContainer)
        
        # Clear existing synchronously
        for child in list(container.children):
            child.remove()
        
        # Update visibility of buttons
        try:
            self.query_one("#add-store-btn", Button).display = (self.current_category == "stores" and self.editing_item_name is None)
            self.query_one("#back-btn", Button).display = (self.editing_item_name is not None)
        except Exception:
            pass

        # We mount using call_after_refresh to ensure the removals are processed by Textual 
        # before we try to mount new widgets with potentially duplicate IDs.
        def do_mount():
            if self.editing_item_name:
                self.render_item_editor(container)
            elif self.current_category == "globals":
                self.render_globals(container)
            elif self.current_category == "stores":
                self.render_stores(container)
            elif self.current_category == "providers":
                self.render_providers(container)
        
        self.call_after_refresh(do_mount)

    def render_globals(self, container: ScrollableContainer) -> None:
        container.mount(Label("General Configuration", classes="config-label"))
        for k, v in self.config_data.items():
            if not isinstance(v, dict) and not k.startswith("_"):
                container.mount(Label(k))
                container.mount(Input(value=str(v), id=f"global-{k}", classes="config-input"))

    def render_stores(self, container: ScrollableContainer) -> None:
        container.mount(Label("Configured Stores", classes="config-label"))
        stores = self.config_data.get("store", {})
        if not stores:
            container.mount(Static("No stores configured."))
        else:
            # stores is structured as: {type: {name: config}}
            for stype, instances in stores.items():
                if isinstance(instances, dict):
                    for name, conf in instances.items():
                        row = Horizontal(
                            Static(f"{name} ({stype})", classes="item-label"),
                            Button("Edit", id=f"edit-store-{stype}-{name}"),
                            Button("Delete", variant="error", id=f"del-store-{stype}-{name}"),
                            classes="item-row"
                        )
                        container.mount(row)

    def render_providers(self, container: ScrollableContainer) -> None:
        container.mount(Label("Configured Providers", classes="config-label"))
        providers = self.config_data.get("provider", {})
        if not providers:
            container.mount(Static("No providers configured."))
        else:
            for name, _ in providers.items():
                row = Horizontal(
                    Static(name, classes="item-label"),
                    Button("Edit", id=f"edit-provider-{name}"),
                    classes="item-row"
                )
                container.mount(row)

    def render_item_editor(self, container: ScrollableContainer) -> None:
        item_type = str(self.editing_item_type or "")
        item_name = str(self.editing_item_name or "")
        
        # Parse item_type for store-{stype} or just provider
        if item_type.startswith("store-"):
            stype = item_type.replace("store-", "")
            container.mount(Label(f"Editing Store: {item_name} ({stype})", classes="config-label"))
            section = self.config_data.get("store", {}).get(stype, {}).get(item_name, {})
        else:
            container.mount(Label(f"Editing {item_type.capitalize()}: {item_name}", classes="config-label"))
            section = self.config_data.get(item_type, {}).get(item_name, {})
        
        # Show all existing keys
        existing_keys_upper = set()
        for k, v in section.items():
            if k.startswith("_"): continue
            
            # Deduplicate keys case-insensitively (e.g. name vs NAME vs Name)
            k_upper = k.upper()
            if k_upper in existing_keys_upper:
                continue
            existing_keys_upper.add(k_upper)
            
            container.mount(Label(k))
            container.mount(Input(value=str(v), id=f"item-{k}", classes="config-input"))
            
        # If it's a store, we might have required keys
        if item_type.startswith("store-"):
            stype = item_type.replace("store-", "")
            classes = _discover_store_classes()
            if stype in classes:
                required_keys = _required_keys_for(classes[stype])
                for rk in required_keys:
                    # Case-insensitive deduplication (fix path vs PATH)
                    if rk.upper() not in existing_keys_upper:
                        container.mount(Label(rk))
                        container.mount(Input(value="", id=f"item-{rk}", classes="config-input"))

    def create_field(self, name: str, value: Any, id: str) -> Vertical:
        # This method is now unused - we mount labels and inputs directly
        v = Vertical(classes="config-field")
        return v

    def on_list_view_selected(self, event: ListView.Selected) -> None:
        if not event.item: return
        if event.item.id == "cat-globals":
            self.current_category = "globals"
        elif event.item.id == "cat-stores":
            self.current_category = "stores"
        elif event.item.id == "cat-providers":
            self.current_category = "providers"
        
        self.editing_item_name = None
        self.editing_item_type = None
        self.refresh_view()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        bid = event.button.id
        if not bid: return
        
        if bid == "cancel-btn":
            self.dismiss()
        elif bid == "back-btn":
            self.editing_item_name = None
            self.editing_item_type = None
            self.refresh_view()
        elif bid == "save-btn":
            self.save_all()
            self.notify("Configuration saved!")
            # Return to the main list view within the current category
            self.editing_item_name = None
            self.editing_item_type = None
            self.refresh_view()
        elif bid.startswith("edit-store-"):
            parts = bid.replace("edit-store-", "").split("-", 1)
            if len(parts) == 2:
                stype, name = parts
                self.editing_item_type = f"store-{stype}"
                self.editing_item_name = name
                self.refresh_view()
        elif bid.startswith("edit-provider-"):
            self.editing_item_name = bid.replace("edit-provider-", "")
            self.editing_item_type = "provider"
            self.refresh_view()
        elif bid == "add-store-btn":
            # Create a simple dialog or default folder store
            new_name = "new_folder"
            if "store" not in self.config_data:
                self.config_data["store"] = {}
            if "folder" not in self.config_data["store"]:
                self.config_data["store"]["folder"] = {}
            self.config_data["store"]["folder"][new_name] = {"NAME": new_name, "path": ""}
            self.editing_item_type = "store-folder"
            self.editing_item_name = new_name
            self.refresh_view()
        elif bid.startswith("del-store-"):
            parts = bid.replace("del-store-", "").split("-", 1)
            if len(parts) == 2:
                stype, name = parts
                if "store" in self.config_data and stype in self.config_data["store"]:
                    if name in self.config_data["store"][stype]:
                        del self.config_data["store"][stype][name]
            self.refresh_view()

    @on(Input.Changed)
    def on_input_changed(self, event: Input.Changed) -> None:
        if not event.input.id:
            return
        if event.input.id.startswith("global-"):
            key = event.input.id.replace("global-", "")
            self.config_data[key] = event.value
        elif event.input.id.startswith("item-") and self.editing_item_name:
            key = event.input.id.replace("item-", "")
            it = str(self.editing_item_type or "")
            inm = str(self.editing_item_name or "")
            
            # Handle nested store structure
            if it.startswith("store-"):
                stype = it.replace("store-", "")
                if "store" not in self.config_data:
                    self.config_data["store"] = {}
                if stype not in self.config_data["store"]:
                    self.config_data["store"][stype] = {}
                if inm not in self.config_data["store"][stype]:
                    self.config_data["store"][stype][inm] = {}
                self.config_data["store"][stype][inm][key] = event.value
            else:
                # Provider or other top-level sections
                if it not in self.config_data:
                    self.config_data[it] = {}
                if inm not in self.config_data[it]:
                    self.config_data[it][inm] = {}
                self.config_data[it][inm][key] = event.value

    def save_all(self) -> None:
        save_config(self.config_data, config_dir=self.workspace_root)
