<?xml version="1.0" encoding="UTF-8"?>
<!--
  ApplicationSchema.v1.0

  Single source of truth for application-level wiring across all frontends. One
  Application.xml per app declares:
    * the service clients the AppStore / DI container exposes (Services),
    * the navigation tree drawn in the menu + reachable as routes (Navigation),
    * the auth strategy + redirect targets (Auth).

  The generator turns this into AppStoreBase.g.ts / AppRoutes.g.tsx /
  Navigation.g.tsx (React), BaseApp.g.cs / BaseMainWindowMenu.g.xaml (WPF),
  app_routers.g.py (FastAPI) — see the per-target generators for the exact emit
  shapes.

  Per-frontend attributes (`frontends`, `icon`, `path`) let one Application.xml
  drive divergent UIs from one declaration; defaults apply when omitted.
-->
<xs:schema
    xmlns="https://tnventures.fi/modelgenerator/xmlschemas/application/v1"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="https://tnventures.fi/modelgenerator/xmlschemas/application/v1"
    elementFormDefault="qualified">

  <!-- =====================================================================
       Root
       ===================================================================== -->

  <xs:element name="Application">
    <xs:annotation>
      <xs:documentation>Root element — one per application. The generator visits a single Application.xml and emits all the glue files that bind generated Models / Services / ViewModels together into a runnable frontend or backend project.</xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:all>
        <xs:element name="UI"         type="UiType"         minOccurs="0"/>
        <xs:element name="Services"   type="ServicesType"   minOccurs="0"/>
        <xs:element name="Navigation" type="NavigationType" minOccurs="0"/>
        <xs:element name="Auth"       type="AuthType"       minOccurs="0"/>
      </xs:all>
      <xs:attribute name="name"      type="xs:string" use="required">
        <xs:annotation>
          <xs:documentation>Application name. Becomes the AppStore class basename / WPF DI module / FastAPI app title — pick the project's logical name (e.g. "TestApp").</xs:documentation>
        </xs:annotation>
      </xs:attribute>
      <xs:attribute name="namespace" type="xs:string">
        <xs:annotation>
          <xs:documentation>Root namespace for generated C# (WPF + DI registration). Optional; defaults to <c>name</c>. Ignored by React / Python emitters which use module paths instead.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
      <xs:attribute name="viewModelNamespace" type="xs:string">
        <xs:annotation>
          <xs:documentation>Optional C# namespace where the generated ViewModel classes referenced by Navigation Items live (e.g. <c>TestApp.ViewModels</c>). Emitted as a <c>using</c> directive in WPF's <c>BaseMainWindowViewModel.g.cs</c> so the per-Item <c>OpenSingleton&lt;TViewModel&gt;</c> calls resolve. React / RN ignore this attribute.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
      <xs:attribute name="viewNamespace" type="xs:string">
        <xs:annotation>
          <xs:documentation>Optional C# namespace where the generated View partial classes (e.g. <c>ProductListView</c>) live. Defaults to <c>viewModelNamespace</c> when omitted. Required when Views inherit the source Model's namespace (the generator's default) instead of co-locating with ViewModels — used in WPF's <c>BasePageDataTemplates.g.xaml</c> to declare a <c>vw:</c> xmlns prefix for View element references. React / RN ignore this attribute.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
      <xs:attribute name="viewModelAssembly" type="xs:string">
        <xs:annotation>
          <xs:documentation>Optional WPF assembly hosting the ViewModel / View types. Used in the xmlns clause of the generated <c>BaseMainWindowMenu.g.xaml</c> + <c>BasePageDataTemplates.g.xaml</c> (<c>clr-namespace:NS;assembly=Asm</c>). Defaults to the application <c>namespace</c> when omitted.</xs:documentation>
        </xs:annotation>
      </xs:attribute>
    </xs:complexType>
  </xs:element>

  <!-- =====================================================================
       UI — per-app UI defaults (view layout, icon library, etc.)
       ===================================================================== -->

  <xs:complexType name="UiType">
    <xs:annotation>
      <xs:documentation>Per-application UI defaults. Scopes the framework-level switches that apply across every view (single vs. tabbed multi-view layout, future icon-library / layout-density knobs). Omit the element entirely to take the per-attribute defaults.</xs:documentation>
    </xs:annotation>
    <xs:attribute name="viewMode" type="ViewModeEnum" default="Single">
      <xs:annotation>
        <xs:documentation>Selects between two layout models: `Single` shows one View at a time (today's default — React: route swaps, WPF: ContentControl); `Tabbed` lets multiple Update / Read Views stay open side-by-side with independent VM instances per tab (React: TabHost over AppRoutes, WPF: TabControl bound to PageManager.OpenViewModels). Closing a dirty tab triggers the framework save/discard confirm dialog regardless of mode.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="orientation" type="OrientationEnum" default="Horizontal">
      <xs:annotation>
        <xs:documentation>Navigation placement. `Horizontal` (default) is the traditional top bar (React: Bootstrap Navbar). `Vertical` is a Claude/ChatGPT-style left sidebar: a collapsible icon-first rail with a toggle, plus a bottom-docked user/account item (see Item `dock`). WPF parity is a follow-up.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <xs:simpleType name="ViewModeEnum">
    <xs:annotation>
      <xs:documentation>UI view-layout selector. `Single` = one view at a time (route-swap / ContentControl). `Tabbed` = multiple views open simultaneously in a tab strip, each with independent VM state.</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:enumeration value="Single"/>
      <xs:enumeration value="Tabbed"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:simpleType name="OrientationEnum">
    <xs:annotation>
      <xs:documentation>Navigation orientation. `Horizontal` = traditional top bar. `Vertical` = left sidebar rail (Claude-style).</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:enumeration value="Horizontal"/>
      <xs:enumeration value="Vertical"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- =====================================================================
       Services
       ===================================================================== -->

  <xs:complexType name="ServicesType">
    <xs:annotation>
      <xs:documentation>Service clients each frontend wires into its AppStore / App.Current / DI container. The Python backend uses these to drive `include_router` calls in main.py; frontends use the alias as the property name on AppStore.</xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="Service" type="ServiceRefType" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="ServiceRefType">
    <xs:attribute name="type" type="xs:string" use="required">
      <xs:annotation>
        <xs:documentation>Type name of an existing Service (the `name=` attribute on a Service.xml). The generator looks up the service in its `-servicePath` index to resolve the client class emitted into AppStore / DI.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="name" type="xs:string">
      <xs:annotation>
        <xs:documentation>Property name the frontend AppStore exposes for this service. Defaults to the camelCased `type` value + "Client" (e.g. type="ApiUserService" -> name="apiUserServiceClient"). Set explicitly to share a single accessor across multiple services (e.g. name="service") or to align with hand-written code.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="namespace" type="xs:string">
      <xs:annotation>
        <xs:documentation>Optional C# / TS module path where the generated service-client type lives. Required by WPF (emitted as a `using` directive in BaseApp.g.cs) when the client is not in the same namespace as the App class. React uses module-relative paths and ignores this attribute.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="frontends" type="xs:string">
      <xs:annotation>
        <xs:documentation>Optional comma-separated list of frontends that should wire this service (e.g. "React,Wpf"). Omit to wire on every target. Useful when a service is consumed only by one frontend (e.g. an admin API used solely by WPF).</xs:documentation>
      </xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <!-- =====================================================================
       Navigation
       ===================================================================== -->

  <xs:complexType name="NavigationType">
    <xs:annotation>
      <xs:documentation>Tree of menu entries. Top-level Items + Groups become the root menu; Groups nest sub-menus. Each Item also becomes a route (React/RN) or a registered VM page (WPF). Item order is preserved on every target.</xs:documentation>
    </xs:annotation>
    <xs:choice maxOccurs="unbounded">
      <xs:element name="Item"  type="NavigationItemType"/>
      <xs:element name="Group" type="NavigationGroupType"/>
    </xs:choice>
  </xs:complexType>

  <xs:complexType name="NavigationGroupType">
    <xs:annotation>
      <xs:documentation>A menu folder. Holds nested Items / sub-Groups; doesn't navigate anywhere itself. Children inherit Group-level `frontends` unless they override it.</xs:documentation>
    </xs:annotation>
    <xs:choice maxOccurs="unbounded">
      <xs:element name="Item"  type="NavigationItemType"/>
      <xs:element name="Group" type="NavigationGroupType"/>
    </xs:choice>
    <xs:attribute name="label"     type="xs:string" use="required">
      <xs:annotation>
        <xs:documentation>Menu label. Supports the framework's standard multi-language syntax: `English[fi]Finnish[sv]Swedish`.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="icon"      type="xs:string">
      <xs:annotation>
        <xs:documentation>Optional icon identifier. Honored by WPF (MahApps Material icons) and React Native (Ionicons). React/web honors when an icon set is configured in the runtime; otherwise rendered as text only.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="frontends" type="xs:string">
      <xs:annotation>
        <xs:documentation>Comma-separated list of frontends to emit this group on. Inherited by children unless they declare their own `frontends`.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <xs:complexType name="NavigationItemType">
    <xs:annotation>
      <xs:documentation>A navigable menu entry. Either binds to a generated ViewModel (the framework knows its view + user-right) or to a hand-written View (anonymous pages like Home / About). Exactly one of `viewModel` or `view` must be set.</xs:documentation>
    </xs:annotation>
    <xs:attribute name="label"     type="xs:string" use="required">
      <xs:annotation>
        <xs:documentation>Menu label. Supports `English[fi]Finnish` syntax.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="viewModel" type="xs:string">
      <xs:annotation>
        <xs:documentation>Name of a generated ViewModel (matches its class name, e.g. `ApiProductListViewModel`). The generator resolves the matching View, requireUserRight bucket, and route from the VM. Mutually exclusive with `view`.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="view"      type="xs:string">
      <xs:annotation>
        <xs:documentation>Name of a hand-written view component (e.g. `HomePage`, `AboutPage`). Used for pages outside the generated VM pipeline. Mutually exclusive with `viewModel`.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="path"      type="xs:string">
      <xs:annotation>
        <xs:documentation>Optional path of the view's source file, relative to the frontend's output root (e.g. `./views/modelViews/ApiProductListView/ApiProductListView.g`). Omit to use the default per-target convention: React uses `./views/modelViews/{ViewName}/{ViewName}.g` for VM-backed items and `./views/screens/{ViewName}/{ViewName}` for hand-written views. Reserved buckets: `./views/pages/` for `mode=Page` ViewModels and `./views/assistants/` for chat clients. Set explicitly when a project organises its views under a non-default directory layout.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="route"     type="xs:string">
      <xs:annotation>
        <xs:documentation>React/web route URL (e.g. `/`, `/products/:id?`). Optional — generator derives a default from the bound VM/view name when omitted. WPF + React Native ignore this attribute; their routing is identity-based.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="icon"      type="xs:string">
      <xs:annotation>
        <xs:documentation>Icon identifier shown next to the menu label on icon-capable frontends.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="anonymous" type="xs:boolean" default="false">
      <xs:annotation>
        <xs:documentation>True for pages that don't require authentication (Home, About, public landing). Generator skips ProtectedRoute wrapping / WPF login redirect.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="requireUserRight" type="xs:string">
      <xs:annotation>
        <xs:documentation>Optional override for the user-right bucket guarding this route. Defaults to the bound VM's bucket (auto-derived from the VM name, mirroring the per-VM rights contract). Set when the route should be guarded by a different bucket than the VM uses internally (e.g. AdminOnly wrapper around a public-VM page).</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="frontends" type="xs:string">
      <xs:annotation>
        <xs:documentation>Comma-separated list of frontends to emit this Item on (e.g. "React,Wpf"). Omit to emit on every target.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="showInMenu" type="xs:boolean" default="true">
      <xs:annotation>
        <xs:documentation>When false, the Item still registers as a navigable route but isn't drawn in the visible menu. Use for detail pages reachable only by code-driven navigation (e.g. ApiProductUpdateView is opened via the list's Edit button, not the top menu).</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="dock" type="DockEnum" default="Top">
      <xs:annotation>
        <xs:documentation>Vertical-sidebar dock position (UI orientation="Vertical" only; ignored by the horizontal top bar). `Top` (default) flows the item in the main rail. `Bottom` pins it to the sidebar footer — the slot for the user/account item (avatar + name + menu).</xs:documentation>
      </xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <xs:simpleType name="DockEnum">
    <xs:annotation>
      <xs:documentation>Vertical-sidebar dock position. `Top` = main rail; `Bottom` = pinned footer (user/account slot).</xs:documentation>
    </xs:annotation>
    <xs:restriction base="xs:string">
      <xs:enumeration value="Top"/>
      <xs:enumeration value="Bottom"/>
    </xs:restriction>
  </xs:simpleType>

  <!-- =====================================================================
       Auth
       ===================================================================== -->

  <xs:complexType name="AuthType">
    <xs:annotation>
      <xs:documentation>Auth strategy + redirect targets the generator wires into ProtectedRoute / WPF login flow / React Native auth navigator. Omit the element entirely on apps that don't authenticate.

Two ways to declare how users sign in:
  1. `strategy="..."` (single mechanism) — the original shorthand. Still fully supported.
  2. `&lt;Methods&gt;` (multiple login-screen options, issue #153) — one app offers several buttons on the same login screen, e.g. "Continue with Google" / "Continue with Apple" / form fields. When `&lt;Methods&gt;` is present it WINS; `strategy` becomes optional. All methods converge on the same AuthenticationReply, so downstream gating (RequireUserRight / ProtectedRoute) is identical regardless of which method the user picked.</xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="Methods" type="AuthMethodsType" minOccurs="0" maxOccurs="1"/>
    </xs:sequence>
    <xs:attribute name="strategy"      type="AuthStrategyType" use="optional">
      <xs:annotation>
        <xs:documentation>How users sign in (single-mechanism shorthand). `FormCredentials` = username+password POST to /auth/form. `WindowsAuth` = Negotiate / Windows-domain identity. `Bearer` = pre-issued token (e.g. SSO). `Anonymous` = no auth, everything public. Optional: supply EITHER this OR `&lt;Methods&gt;`. When both are present, `&lt;Methods&gt;` wins and `strategy` is ignored. When neither is present the app defaults to an interactive FormCredentials login.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="loginView"     type="xs:string">
      <xs:annotation>
        <xs:documentation>View component shown for the login form. Default: `LoginView`. Generator wires ProtectedRoute to redirect here on missing auth.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="signUpView"    type="xs:string">
      <xs:annotation>
        <xs:documentation>Optional. Registration / sign-up view — typically a Wizard ViewModel's View (e.g. a sign-up wizard). The generator routes it at /signup as an ANONYMOUS pre-auth route (outside ProtectedRoute — the caller isn't logged in yet), so the app can offer a "Sign up" link beside Login. Pair the wizard's first step with `authMethods` to let the new user authenticate mid-flow. Omit for apps with no self-service registration.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="forbiddenView" type="xs:string">
      <xs:annotation>
        <xs:documentation>View component shown when an authenticated user lacks the required user-right for the requested route. Default: `ForbiddenPage`.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="defaultView"   type="xs:string">
      <xs:annotation>
        <xs:documentation>View component shown at the application root path. Default: `HomePage`. Generator wires this as the `/` route on React / startup screen on WPF / initial screen on React Native.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="service"       type="xs:string">
      <xs:annotation>
        <xs:documentation>Optional reference to the `&lt;Service type="..."/&gt;` that carries the authentication call (e.g. `AuthenticateWindowsCredentials` / `AuthenticateFormCredentials`). Defaults to the first `&lt;Service&gt;` when omitted. The generated `AuthenticateOnStartupAsync` invokes the chosen client's auth method per the `strategy`.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
  </xs:complexType>

  <xs:simpleType name="AuthStrategyType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="FormCredentials"/>
      <xs:enumeration value="WindowsAuth"/>
      <xs:enumeration value="Bearer"/>
      <xs:enumeration value="Anonymous"/>
    </xs:restriction>
  </xs:simpleType>

  <xs:complexType name="AuthMethodsType">
    <xs:annotation>
      <xs:documentation>Ordered list of login-screen auth methods (issue #153). Render order on the login screen follows document order. At least one Method is required when the element is present.</xs:documentation>
    </xs:annotation>
    <xs:sequence>
      <xs:element name="Method" type="AuthMethodType" minOccurs="1" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

  <xs:complexType name="AuthMethodType">
    <xs:annotation>
      <xs:documentation>One selectable login option. `FormCredentials` renders username+password fields and POSTs to /auth/form. `Google` / `Apple` render a "Continue with ..." button that runs the provider's JS SDK, then exchanges the returned id_token at /auth/google or /auth/apple (server validates the token against the provider JWKS). All converge on the same AuthenticationReply.</xs:documentation>
    </xs:annotation>
    <xs:attribute name="type" type="AuthMethodKindType" use="required">
      <xs:annotation>
        <xs:documentation>Method kind: `FormCredentials` | `Google` | `Apple` | `Email`. `Email` is passwordless: the user submits an email, the server emails a short-lived confirm link, and clicking it signs the user in.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="clientId" type="xs:string" use="optional">
      <xs:annotation>
        <xs:documentation>OAuth public client id for `Google` / `Apple` — handed to the provider's JS SDK on the client and validated as the id_token audience server-side. Required for Google / Apple; ignored for FormCredentials.</xs:documentation>
      </xs:annotation>
    </xs:attribute>
    <xs:attribute name="verification" use="optional">
      <xs:annotation>
        <xs:documentation>For `Email` only. `Link` (default) emails a magic confirm link that navigates the browser to /confirm-email — fine for a standalone login screen, but it destroys an in-progress wizard's state. `Code` emails a short one-time code the user types back in place (no navigation), so an email step inside a sign-up wizard keeps its state. Ignored for non-Email methods.</xs:documentation>
      </xs:annotation>
      <xs:simpleType>
        <xs:restriction base="xs:string">
          <xs:enumeration value="Link"/>
          <xs:enumeration value="Code"/>
        </xs:restriction>
      </xs:simpleType>
    </xs:attribute>
  </xs:complexType>

  <xs:simpleType name="AuthMethodKindType">
    <xs:restriction base="xs:string">
      <xs:enumeration value="FormCredentials"/>
      <xs:enumeration value="Google"/>
      <xs:enumeration value="Apple"/>
      <xs:enumeration value="Email"/>
    </xs:restriction>
  </xs:simpleType>

</xs:schema>
