// src/services/platform.ts
// Copyright (C) 2026 Rob Colbert <rob.colbert@openplatform.us>
// Licensed under the Apache License, Version 2.0

import env from "../config/env.ts";

import assert from "node:assert";
import path from "node:path";
import os from "node:os";

import { GadgetService } from "../lib/service.ts";
import {
  DroneStatus,
  IChatSession,
  IChatTurn,
  IDroneRegistration,
  IUser,
  Types,
} from "@gadget/api";

interface PlatformApiResponse {
  success: boolean;
  message?: string;
}

interface PlatformRegistrationResponse extends PlatformApiResponse {
  data: IDroneRegistration;
}

interface ChatSessionContextResponse extends PlatformApiResponse {
  data: IChatTurn[];
}

class PlatformService extends GadgetService {
  registration: IDroneRegistration | undefined;

  get name(): string {
    return "PlatformService";
  }
  get slug(): string {
    return "svc:platform";
  }

  async start(): Promise<void> {
    this.log.info("started");
  }

  async stop(): Promise<void> {
    this.log.info("stopped");
  }

  async register(
    email: string,
    password: string,
    workspaceDir: string,
    workspaceId: string,
  ): Promise<IDroneRegistration> {
    const url = this.getApiUrl("/drone/registration");
    this.log.info("registering with Gadget Code Platform", {
      workspaceId,
      email,
      url,
    });
    const body = JSON.stringify({
      email,
      password,
      hostname: os.hostname(),
      workspaceDir,
      workspaceId,
    });
    const response = await fetch(url, {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        "Content-Length": body.length.toString(),
        "X-Gadget-Key": env.platform.gadgetKey,
      },
      body,
    });

    const json = (await response.json()) as PlatformRegistrationResponse;
    this.log.debug("platform registration response", json);
    if (!json.success) {
      const error = new Error("failed to register drone with Platform");
      error.name = "PlatformError";
      error.statusCode = response.status;
      throw error;
    }

    if (!json.data || !json.data._id) {
      const error = new Error(
        "registration response did not contain required data",
      );
      error.name = "PlatformError";
      throw error;
    }

    if (!json.data.user || !(json.data.user as IUser)._id) {
      const error = new Error(
        "registration response did not contain required user account data",
      );
      error.name = "PlatformError";
      throw error;
    }

    this.registration = json.data;

    return json.data;
  }

  async unregister(): Promise<void> {
    if (!this.registration) {
      return;
    }

    const url = this.getApiUrl(`/drone/registration/${this.registration._id}`);
    const body = JSON.stringify({ registration: this.registration });
    const response = await fetch(url, {
      method: "DELETE",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        "Content-Length": body.length.toString(),
        "X-Gadget-Key": env.platform.gadgetKey,
      },
      body,
    });

    const json = (await response.json()) as PlatformRegistrationResponse;
    if (!json.success) {
      const error = new Error("failed to register drone with Platform");
      error.name = "PlatformError";
      error.statusCode = response.status;
      throw error;
    }
  }

  async setStatus(status: DroneStatus): Promise<void> {
    assert(
      this.registration,
      "must register with platform before setting status",
    );

    const url = this.getApiUrl(
      `/drone/registration/${this.registration._id}/status`,
    );
    const body = JSON.stringify({ status });
    const response = await fetch(url, {
      method: "PUT",
      headers: {
        Accept: "application/json",
        "Content-Type": "application/json",
        "Content-Length": body.length.toString(),
        "X-Gadget-Key": env.platform.gadgetKey,
      },
      body,
    });

    const json = (await response.json()) as PlatformRegistrationResponse;
    if (!json.success) {
      const error = new Error("failed to register drone with Platform");
      error.name = "PlatformError";
      error.statusCode = response.status;
      throw error;
    }

    this.log.info("drone status updated on platform", { status });
  }

  async getChatSessionContext(
    session: IChatSession,
  ): Promise<ChatSessionContextResponse> {
    assert(
      this.registration,
      "must register with platform before setting status",
    );

    const url = this.getApiUrl(`/chat-sessions/${session._id}/turns`);
    const response = await fetch(url, {
      method: "GET",
      headers: {
        Accept: "application/json",
        "X-Gadget-Key": env.platform.gadgetKey,
      },
    });

    const json = (await response.json()) as ChatSessionContextResponse;
    if (!json.success) {
      const error = new Error("failed to retrieve chat session context");
      error.name = "PlatformError";
      error.statusCode = response.status;
      throw error;
    }

    this.log.info("chat session context received", {
      turnCount: json.data.length,
    });
    return json;
  }

  getApiUrl(url: string): string {
    return `${env.platform.baseUrl}/api/v1${url}`;
  }
}

export default new PlatformService();
