// KopScript declarations for the kopular package — what `using "kopular";`
// resolves to (package.json's "kopscript" field). Never compiled itself: a
// consuming file imports exactly the bindings it uses, straight from the
// modules named below. test/declarations.test.ts checks every Kopular
// declaration here against the real source it describes.

// ---------- Browser globals ----------

extern class Event {
  Element target { get; }
  string key { get; }
  void preventDefault();
  void stopPropagation();
};

extern class Element {
  string textContent { get; set; }
  string innerHTML { get; set; }
  string id { get; set; }
  string className { get; set; }
  string value { get; set; }
  string placeholder { get; set; }
  string href { get; set; }
  string src { get; set; }
  string alt { get; set; }
  bool disabled { get; set; }
  bool checked { get; set; }
  void appendChild(Element child);
  void replaceChild(Element newChild, Element oldChild);
  void insertBefore(Element newChild, Element? referenceChild);
  void removeChild(Element child);
  void setAttribute(string name, string value);
  string? getAttribute(string name);
  void removeAttribute(string name);
  void addEventListener(string eventType, (Event) => void handler);
  void removeEventListener(string eventType, (Event) => void handler);
  Element querySelector(string selector);
  Element? closest(string selector);
  void focus();
};

extern class Document {
  Element createElement(string tagName);
  Element getElementById(string id);
  Element querySelector(string selector);
  Element body { get; }
  Element head { get; }
  string title { get; set; }
};

extern class Location {
  string pathname { get; }
  string search { get; }
  string href { get; }
};

extern class History {
  void pushState(string historyState, string title, string url);
  void back();
};

extern class Window {
  void addEventListener(string eventType, (Event) => void handler);
};

// What fetch() resolves to — see Http below.
extern class Response {
  bool ok { get; }
  number status { get; }
  task<string> text();
};

extern Document document;
extern Location location;
extern History history;
extern Window window;

extern number SetTimeout(() => void callback, number ms) as "setTimeout";
extern void ClearTimeout(number timerId) as "clearTimeout";
extern number ParseFloat(string text) as "parseFloat";

// ---------- Kopular ----------

extern class VElement {
  static VElement Create(string tag);
  // Embeds a live child Component as this slot's content.
  static VElement Mount(Component component);
  string TextContent { get; set; }
  string ClassName { get; set; }
  string Id { get; set; }
  string Value { get; set; }
  string RawHtml { get; set; }
  bool Disabled { get; set; }
  bool Checked { get; set; }
  (Event) => void OnClick { get; set; }
  (Event) => void OnInput { get; set; }
  (Event) => void OnBlur { get; set; }
  (Event) => void OnChange { get; set; }
  void AppendChild(VElement child);
  void SetAttr(string name, string value);
} from "kopular/velement";

extern class Component {
  constructor();
  virtual VElement Render();
  virtual VElement RenderError(string message);
  virtual void AfterRender(Element root);
  virtual void OnUnmount();
  void Mount(Element parent);
  void Update();
} from "kopular/component";

// The runtime half of `styles from "./x.css";` — the compiler calls it for you.
extern class ScopedStyles {
  static void Inject(string scopeId, string css);
} from "kopular/vdom";

extern class Router : Component {
  constructor(Component notFoundPage);
  void AddRoute(string path, Component page);
  void AddLazyRoute(string path, () => task<Component> loader);
  string[] AllPaths();
  void SetGuard(string redirectPath, (string) => bool guard);
  void Navigate(string path);
  string Param { get; }
  string Params(string name);
  string Query(string key);
  virtual VElement BuildLoadingPlaceholder();
} from "kopular/router";

extern VElement If(bool condition, () => VElement whenTrue, () => VElement whenFalse) from "kopular/directives";

extern class Http {
  static task<Response> Get(string url);
  static task<Response> Post(string url, string jsonBody);
  static task<Response> Put(string url, string jsonBody);
  static task<Response> Patch(string url, string jsonBody);
  static task<Response> Delete(string url);
} from "kopular/http";

extern class FormField<T> {
  constructor(T initial, (T) => string? validate);
  state<T> Value { get; }
  state<string?> Error { get; }
  state<bool> Touched { get; }
  void Touch();
  bool Valid();
} from "kopular/forms";

extern class Validators {
  static string? Required(string value);
  static string? MinLength(string value, number min);
  static string? MaxLength(string value, number max);
  static string? Email(string value);
  static string? Min(number value, number min);
  static string? Max(number value, number max);
} from "kopular/forms";

// Chain validators into the single (T) => string? a FormField takes. Real
// generic free functions in forms.ks; without these declared here, a
// consumer using `using "kopular";` couldn't reach them at all.
extern (T) => string? CombineValidators2<T>((T) => string? v1, (T) => string? v2) from "kopular/forms";
extern (T) => string? CombineValidators3<T>((T) => string? v1, (T) => string? v2, (T) => string? v3) from "kopular/forms";

extern class Computed1<A, R> {
  constructor(state<A> source, (A) => R compute);
  state<R> Value { get; }
} from "kopular/computed";

extern class Computed2<A, B, R> {
  constructor(state<A> a, state<B> b, (A, B) => R compute);
  state<R> Value { get; }
} from "kopular/computed";

extern enum AsyncStatus { Loading, Success, Failure } from "kopular/resource";

extern class Resource<T> {
  constructor(task<T> operation);
  state<AsyncStatus> Status { get; }
  state<T?> Data { get; }
  state<string?> Error { get; }
} from "kopular/resource";

// Resolves after `ms` milliseconds: `await Delay(500);`
extern task Delay(number ms) from "kopular/timers";
