from dataclasses import dataclass

import flet as ft

DARK_PAIR: dict[str, str] = {
    "Aurora": "Midnight",
    "Midnight": "Aurora",
    "Lime": "Obsidian",
    "Rose": "Obsidian",
    "Obsidian": "Lime",
}

THEMES: dict[str, dict] = {
    "Aurora": {
        "primary": "#22D3EE",
        "surface": "#FFFFFF",
        "surface_alt": "#F0F9FF",
        "on_surface": "#0F172A",
        "muted": "#64748B",
        "outline": "#E2E8F0",
        "tag_bg": "#CFFAFE",
        "tag_text": "#0E7490",
        "dot": "#22D3EE",
        "subtitle": "Suave, brilhante e acolhedor",
    },
    "Midnight": {
        "primary": "#818CF8",
        "surface": "#1E293B",
        "surface_alt": "#0F172A",
        "on_surface": "#F1F5F9",
        "muted": "#94A3B8",
        "outline": "#334155",
        "tag_bg": "#312E81",
        "tag_text": "#C7D2FE",
        "dot": "#818CF8",
        "subtitle": "Elegante, técnico e profundo",
    },
    "Lime": {
        "primary": "#84CC16",
        "surface": "#FFFFFF",
        "surface_alt": "#F7FEE7",
        "on_surface": "#14532D",
        "muted": "#4D7C0F",
        "outline": "#D9F99D",
        "tag_bg": "#ECFCCB",
        "tag_text": "#3F6212",
        "dot": "#84CC16",
        "subtitle": "Vivo, leve e energético",
    },
    "Rose": {
        "primary": "#FB7185",
        "surface": "#FFFFFF",
        "surface_alt": "#FFF1F2",
        "on_surface": "#4C0519",
        "muted": "#9F1239",
        "outline": "#FFE4E6",
        "tag_bg": "#FFE4E6",
        "tag_text": "#9F1239",
        "dot": "#FB7185",
        "subtitle": "Romântico, quente e sofisticado",
    },
    "Obsidian": {
        "primary": "#E2E8F0",
        "surface": "#09090B",
        "surface_alt": "#18181B",
        "on_surface": "#FAFAFA",
        "muted": "#A1A1AA",
        "outline": "#27272A",
        "tag_bg": "#27272A",
        "tag_text": "#D4D4D8",
        "dot": "#E2E8F0",
        "subtitle": "Sólido, minimalista e atemporal",
    },
}

_CHECKER_BG = "#E8E8E8"


@ft.observable
@dataclass
class AppState:
    """Estado global reativo da aplicação."""

    theme_name: str = "Aurora"
    dark_mode: bool = False
    logo_light: str = ""
    logo_dark: str = ""


def th(state: AppState) -> dict:
    """Retorna as cores do tema ativo."""
    return THEMES[state.theme_name]


def active_logo(state: AppState) -> str:
    """Retorna o logotipo adequado ao modo atual, com fallback para o outro."""
    if state.dark_mode:
        return state.logo_dark or state.logo_light
    return state.logo_light or state.logo_dark


@ft.component
def Navbar(state: AppState):
    """Barra superior com logotipo contextual e indicador do tema ativo."""
    c = th(state)
    logo_src = active_logo(state)

    if logo_src:
        brand = ft.Image(src=logo_src, height=36, fit=ft.BoxFit.CONTAIN)
    else:
        brand = ft.Row(
            [
                ft.Container(
                    width=32,
                    height=32,
                    border_radius=10,
                    bgcolor=c["tag_bg"],
                    alignment=ft.Alignment.CENTER,
                    content=ft.Icon(
                        ft.Icons.PALETTE_ROUNDED, color=c["primary"], size=16
                    ),
                ),
                ft.Text(
                    "Theme Studio",
                    size=16,
                    weight=ft.FontWeight.W_800,
                    color=c["primary"],
                ),
            ],
            spacing=10,
            vertical_alignment=ft.CrossAxisAlignment.CENTER,
        )

    return ft.Container(
        content=ft.Row(
            [
                brand,
                ft.Container(
                    padding=ft.Padding.symmetric(horizontal=12, vertical=6),
                    border_radius=999,
                    bgcolor=c["tag_bg"],
                    content=ft.Text(
                        f"● {state.theme_name}",
                        size=11,
                        weight=ft.FontWeight.W_700,
                        color=c["tag_text"],
                    ),
                ),
            ],
            alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
            vertical_alignment=ft.CrossAxisAlignment.CENTER,
        ),
        padding=ft.Padding.symmetric(horizontal=24, vertical=14),
        bgcolor=c["surface"],
        border=ft.Border.only(bottom=ft.BorderSide(1, c["outline"])),
    )


@ft.component
def ThemeOption(state: AppState, name: str):
    """Item selecionável de tema na sidebar."""
    c = THEMES[name]
    selected = state.theme_name == name

    def on_tap(_):
        state.theme_name = name

    return ft.GestureDetector(
        on_tap=on_tap,
        content=ft.Container(
            content=ft.Row(
                [
                    ft.Container(
                        width=10, height=10, border_radius=5, bgcolor=c["dot"]
                    ),
                    ft.Column(
                        [
                            ft.Text(
                                name,
                                size=13,
                                weight=ft.FontWeight.W_700,
                                color=c["on_surface"],
                            ),
                            ft.Text(c["subtitle"], size=10, color=c["muted"]),
                        ],
                        spacing=1,
                        expand=True,
                    ),
                    ft.Icon(
                        (
                            ft.Icons.CHECK_CIRCLE_ROUNDED
                            if selected
                            else ft.Icons.RADIO_BUTTON_UNCHECKED
                        ),
                        color=c["primary"] if selected else c["muted"],
                        size=16,
                    ),
                ],
                spacing=10,
                vertical_alignment=ft.CrossAxisAlignment.CENTER,
            ),
            padding=ft.Padding.symmetric(horizontal=14, vertical=12),
            border_radius=14,
            bgcolor=c["surface_alt"] if selected else c["surface"],
            border=ft.Border.all(
                2 if selected else 1, c["primary"] if selected else c["outline"]
            ),
        ),
    )


def _logo_card(
    c: dict,
    title: str,
    subtitle: str,
    logo_path: str,
    on_pick,
    on_clear,
) -> ft.Container:
    """Card de upload de logotipo para um modo específico (claro ou escuro)."""
    if logo_path:
        preview = ft.Container(
            height=72,
            border_radius=10,
            bgcolor=_CHECKER_BG,
            alignment=ft.Alignment.CENTER,
            content=ft.Image(src=logo_path, height=48, fit=ft.BoxFit.CONTAIN),
        )
        actions = ft.Row(
            [
                ft.TextButton(
                    "Trocar", style=ft.ButtonStyle(color=c["primary"]), on_click=on_pick
                ),
                ft.TextButton(
                    "Remover", style=ft.ButtonStyle(color=c["muted"]), on_click=on_clear
                ),
            ],
            spacing=0,
            alignment=ft.MainAxisAlignment.CENTER,
        )
        inner = ft.Column([preview, actions], spacing=6)
    else:
        inner = ft.GestureDetector(
            on_tap=on_pick,
            content=ft.Container(
                height=72,
                border_radius=10,
                bgcolor=_CHECKER_BG,
                alignment=ft.Alignment.CENTER,
                content=ft.Column(
                    [
                        ft.Icon(
                            ft.Icons.ADD_PHOTO_ALTERNATE_OUTLINED,
                            color="#AAAAAA",
                            size=22,
                        ),
                        ft.Text("Clique para adicionar", size=11, color="#888888"),
                    ],
                    horizontal_alignment=ft.CrossAxisAlignment.CENTER,
                    spacing=4,
                ),
            ),
        )

    return ft.Container(
        padding=ft.Padding.all(14),
        border_radius=16,
        bgcolor=c["surface"],
        border=ft.Border.all(1, c["outline"]),
        content=ft.Column(
            [
                ft.Row(
                    [
                        ft.Text(
                            title,
                            size=12,
                            weight=ft.FontWeight.W_700,
                            color=c["on_surface"],
                        ),
                        ft.Text(subtitle, size=11, color=c["muted"]),
                    ],
                    spacing=6,
                    vertical_alignment=ft.CrossAxisAlignment.CENTER,
                ),
                inner,
            ],
            spacing=8,
        ),
    )


@ft.component
def Sidebar(state: AppState):
    """Painel lateral com seleção de tema, dark mode e logotipos separados por modo."""
    c = th(state)

    def on_dark_change(e):
        state.dark_mode = e.control.value
        state.theme_name = DARK_PAIR.get(state.theme_name, state.theme_name)

    dark_row = ft.Container(
        content=ft.Row(
            [
                ft.Text(
                    "Dark mode",
                    size=13,
                    weight=ft.FontWeight.W_600,
                    color=c["on_surface"],
                ),
                ft.Switch(
                    value=state.dark_mode,
                    active_color=c["primary"],
                    on_change=on_dark_change,
                ),
            ],
            alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
            vertical_alignment=ft.CrossAxisAlignment.CENTER,
        ),
        padding=ft.Padding.symmetric(horizontal=14, vertical=8),
        border_radius=14,
        bgcolor=c["surface_alt"],
        border=ft.Border.all(1, c["outline"]),
    )

    async def pick_light(_):
        picker = ft.FilePicker()
        files = await picker.pick_files(
            dialog_title="Logotipo para tema claro",
            file_type=ft.FilePickerFileType.IMAGE,
        )
        if files and files[0].path:
            state.logo_light = files[0].path

    async def pick_dark(_):
        picker = ft.FilePicker()
        files = await picker.pick_files(
            dialog_title="Logotipo para tema escuro",
            file_type=ft.FilePickerFileType.IMAGE,
        )
        if files and files[0].path:
            state.logo_dark = files[0].path

    def clear_light(_):
        state.logo_light = ""

    def clear_dark(_):
        state.logo_dark = ""

    def section_label(label: str) -> ft.Text:
        return ft.Text(label, size=10, weight=ft.FontWeight.W_700, color=c["muted"])

    return ft.Container(
        content=ft.Column(
            [
                section_label("ESTILO"),
                *[ThemeOption(state, name) for name in THEMES],
                dark_row,
                section_label("IDENTIDADE"),
                _logo_card(
                    c,
                    title="☀  Tema claro",
                    subtitle="· exibido no modo light",
                    logo_path=state.logo_light,
                    on_pick=pick_light,
                    on_clear=clear_light,
                ),
                _logo_card(
                    c,
                    title="☾  Tema escuro",
                    subtitle="· exibido no modo dark",
                    logo_path=state.logo_dark,
                    on_pick=pick_dark,
                    on_clear=clear_dark,
                ),
                ft.Text(
                    "PNG, SVG ou JPG · aparece na navbar", size=10, color=c["muted"]
                ),
            ],
            spacing=8,
            scroll=ft.ScrollMode.AUTO,
        ),
        padding=ft.Padding.all(20),
        border_radius=24,
        bgcolor=c["surface"],
        border=ft.Border.all(1, c["outline"]),
    )


@ft.component
def Hero(state: AppState):
    """Bloco de destaque com título e tags conceituais."""
    c = th(state)

    def pill(label: str, accent: bool = False) -> ft.Container:
        return ft.Container(
            padding=ft.Padding.symmetric(horizontal=14, vertical=7),
            border_radius=999,
            bgcolor=c["primary"] if accent else c["surface_alt"],
            border=ft.Border.all(0 if accent else 1, c["outline"]),
            content=ft.Text(
                label,
                size=12,
                weight=ft.FontWeight.W_600,
                color=c["surface"] if accent else c["on_surface"],
            ),
        )

    return ft.Container(
        padding=ft.Padding.all(28),
        border_radius=24,
        bgcolor=c["surface"],
        border=ft.Border.all(1, c["outline"]),
        content=ft.Column(
            [
                ft.Container(
                    content=ft.Row(
                        [
                            ft.Container(
                                width=8, height=8, border_radius=4, bgcolor=c["dot"]
                            ),
                            ft.Text(
                                "interface reativa · tema vivo · flet 0.83",
                                size=11,
                                weight=ft.FontWeight.W_700,
                                color=c["tag_text"],
                            ),
                        ],
                        spacing=8,
                        vertical_alignment=ft.CrossAxisAlignment.CENTER,
                    ),
                    padding=ft.Padding.symmetric(horizontal=14, vertical=7),
                    border_radius=999,
                    bgcolor=c["tag_bg"],
                ),
                ft.Text(
                    "Uma interface que chama atenção\nsem pedir desculpas.",
                    size=28,
                    weight=ft.FontWeight.W_800,
                    color=c["on_surface"],
                ),
                ft.Text(
                    "Troque o tema ao lado e veja cada elemento se reorganizar "
                    "com personalidade. UI = f(state) — sem page.update(), "
                    "sem mutação de controle.",
                    size=14,
                    color=c["muted"],
                ),
                ft.Row(
                    [
                        pill("Tema vivo", accent=True),
                        pill("Declarativo"),
                        pill("@ft.observable"),
                        pill("@ft.component"),
                    ],
                    wrap=True,
                    spacing=8,
                    run_spacing=8,
                ),
            ],
            spacing=16,
        ),
    )


@ft.component
def StatsRow(state: AppState):
    """Linha de cartões com métricas do projeto."""
    c = th(state)

    items = [("5", "temas"), ("0", "page.update()"), ("∞", "combinações")]

    return ft.Row(
        [
            ft.Container(
                expand=True,
                padding=ft.Padding.symmetric(horizontal=18, vertical=16),
                border_radius=18,
                bgcolor=c["surface"],
                border=ft.Border.all(1, c["outline"]),
                content=ft.Column(
                    [
                        ft.Text(
                            value,
                            size=26,
                            weight=ft.FontWeight.W_800,
                            color=c["primary"],
                        ),
                        ft.Text(
                            label, size=11, weight=ft.FontWeight.W_600, color=c["muted"]
                        ),
                    ],
                    spacing=3,
                ),
            )
            for value, label in items
        ],
        spacing=10,
        expand=True,
    )


@ft.component
def PreviewCard(state: AppState):
    """Prévia interativa com campos horizontais e botões de ação."""
    c = th(state)

    def divider() -> ft.Container:
        return ft.Container(height=1, bgcolor=c["outline"])

    fields = ft.Row(
        [
            ft.TextField(
                label="Nome do projeto",
                value="Theme Studio",
                filled=True,
                expand=True,
                border_radius=14,
                bgcolor=c["surface_alt"],
                color=c["on_surface"],
                border_color=c["outline"],
                focused_border_color=c["primary"],
                label_style=ft.TextStyle(color=c["muted"]),
            ),
            ft.TextField(
                label="Descrição",
                value="Uma interface bonita vende a ideia antes da explicação.",
                filled=True,
                expand=True,
                multiline=True,
                min_lines=1,
                max_lines=2,
                border_radius=14,
                bgcolor=c["surface_alt"],
                color=c["on_surface"],
                border_color=c["outline"],
                focused_border_color=c["primary"],
                label_style=ft.TextStyle(color=c["muted"]),
            ),
        ],
        spacing=14,
        expand=True,
        vertical_alignment=ft.CrossAxisAlignment.START,
    )

    return ft.Container(
        padding=ft.Padding.all(28),
        border_radius=24,
        bgcolor=c["surface"],
        border=ft.Border.all(1, c["outline"]),
        content=ft.Column(
            [
                ft.Row(
                    [
                        ft.Text(
                            "Prévia da interface",
                            size=16,
                            weight=ft.FontWeight.W_700,
                            color=c["on_surface"],
                        ),
                        ft.Container(
                            padding=ft.Padding.symmetric(horizontal=10, vertical=5),
                            border_radius=999,
                            bgcolor=c["tag_bg"],
                            content=ft.Text(
                                "live",
                                size=10,
                                weight=ft.FontWeight.W_700,
                                color=c["tag_text"],
                            ),
                        ),
                    ],
                    alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
                ),
                ft.Text(
                    "Cada elemento abaixo reage ao tema selecionado.",
                    size=12,
                    color=c["muted"],
                ),
                divider(),
                fields,
                divider(),
                ft.Row(
                    [
                        ft.Button(
                            "Salvar tema",
                            style=ft.ButtonStyle(
                                bgcolor=c["primary"],
                                color=c["surface"],
                                shape=ft.RoundedRectangleBorder(radius=12),
                                padding=ft.Padding.symmetric(
                                    horizontal=20, vertical=14
                                ),
                                elevation=0,
                            ),
                        ),
                        ft.Button(
                            "Ver variações",
                            style=ft.ButtonStyle(
                                bgcolor=ft.Colors.TRANSPARENT,
                                color=c["on_surface"],
                                side=ft.BorderSide(1.5, c["outline"]),
                                shape=ft.RoundedRectangleBorder(radius=12),
                                padding=ft.Padding.symmetric(
                                    horizontal=20, vertical=14
                                ),
                                elevation=0,
                            ),
                        ),
                    ],
                    spacing=10,
                    wrap=True,
                ),
            ],
            spacing=16,
        ),
    )


@ft.component
def AppView(page: ft.Page):
    """Raiz da aplicação — monta layout e sincroniza theme_mode com o estado."""
    state, _ = ft.use_state(AppState())

    def sync_page_theme():
        page.theme_mode = ft.ThemeMode.DARK if state.dark_mode else ft.ThemeMode.LIGHT
        page.update()

    ft.use_effect(sync_page_theme, [state.dark_mode])

    c = th(state)

    sidebar_wrapper = ft.Container(
        content=Sidebar(state),
        col={ft.ResponsiveRowBreakpoint.XS: 12, ft.ResponsiveRowBreakpoint.LG: 3},
    )

    main_content = ft.Column(
        [Hero(state), StatsRow(state), PreviewCard(state)],
        spacing=14,
        scroll=ft.ScrollMode.AUTO,
        expand=True,
    )

    main_wrapper = ft.Container(
        content=main_content,
        expand=True,
        col={ft.ResponsiveRowBreakpoint.XS: 12, ft.ResponsiveRowBreakpoint.LG: 9},
    )

    body = ft.Container(
        expand=True,
        bgcolor=c["surface_alt"],
        padding=ft.Padding.symmetric(horizontal=20, vertical=20),
        content=ft.ResponsiveRow(
            [sidebar_wrapper, main_wrapper],
            spacing=16,
            run_spacing=16,
            vertical_alignment=ft.CrossAxisAlignment.START,
            expand=True,
        ),
    )

    return ft.Column([Navbar(state), body], spacing=0, expand=True)


def main(page: ft.Page):
    page.title = "Theme Studio"
    page.padding = 0
    page.expand = True
    page.theme_mode = ft.ThemeMode.LIGHT
    page.render(AppView, page)


ft.run(main)
