import {
  MatrixActor,
  MatrixRuntime,
  TopicRouter,
  createBrowserNatsTransport,
} from '@open-matrix/sdk';
import type { HiveCastActorCredential } from '@open-matrix/sdk';

class FreshBrowserEchoActor extends MatrixActor {
  static accepts = {
    echo: {},
    getStatus: {},
  };

  onEcho(payload: { message?: string }) {
    return {
      ok: true,
      message: payload.message ?? null,
      actor: 'FreshBrowserEchoActor',
    };
  }

  onGetStatus() {
    return {
      ok: true,
      actor: 'FreshBrowserEchoActor',
      mode: 'browser',
    };
  }
}

async function request(
  transport: Awaited<ReturnType<typeof createBrowserNatsTransport>>,
  mount: string,
  op: string,
  payload: unknown,
): Promise<unknown> {
  const correlationId = `fresh-web-${Date.now()}-${Math.random().toString(16).slice(2)}`;
  const replyTo = `$replies.${correlationId}`;
  let unsubscribe = () => {};
  const response = new Promise<unknown>((resolve, reject) => {
    const timeout = window.setTimeout(() => {
      unsubscribe();
      reject(new Error(`REQUEST_TIMEOUT: ${mount}.${op}`));
    }, 5000);
    unsubscribe = transport.subscribe(replyTo, (value) => {
      window.clearTimeout(timeout);
      unsubscribe();
      resolve(value);
    });
  });

  transport.publish(TopicRouter.inbox(mount), {
    op,
    payload,
    replyTo,
    correlationId,
  });

  return response;
}

class FreshWebActorDemoElement extends HTMLElement {
  private readonly _status = document.createElement('pre');

  connectedCallback(): void {
    this.innerHTML = '';
    this._status.textContent = 'Connecting to HiveCast...';
    this.append(this._status);
    void this._run();
  }

  private async _run(): Promise<void> {
    const credentialResponse = await fetch('/matrix/actor-credential', { method: 'POST' });
    const credential = await credentialResponse.json() as HiveCastActorCredential;
    if (!credentialResponse.ok || credential.ok !== true) {
      throw new Error(`HiveCast credential exchange failed: ${JSON.stringify(credential)}`);
    }
    if (!credential.transport.natsWsUrl) {
      throw new Error('HiveCast actor credential response did not include transport.natsWsUrl');
    }

    const transport = await createBrowserNatsTransport({
      root: credential.root,
      wsUrl: credential.transport.natsWsUrl,
      jwtProvider: async () => ({
        jwt: credential.credentials.jwt,
        seed: credential.credentials.seed,
      }),
    });
    const runtime = new MatrixRuntime({ transport, logging: false });
    await runtime.create(FreshBrowserEchoActor, credential.mount);
    const result = await request(transport, credential.mount, 'echo', {
      message: 'hello-from-fresh-web-page-demo',
    });

    this._status.textContent = JSON.stringify({
      ok: true,
      demo: 'fresh-web-page',
      cloud: credential.cloud,
      space: credential.space,
      root: credential.root,
      mount: credential.mount,
      natsWsUrl: credential.transport.natsWsUrl,
      credentialPipeline: credential.credentialPipeline,
      check: result,
    }, null, 2);
  }
}

customElements.define('fresh-web-actor-demo', FreshWebActorDemoElement);
