import axios from "axios";
import { z } from "zod";

export const accessSchema = z.discriminatedUnion("type", [
	z.object({
		type: z.literal("https"),
		name: z.string(),
		address: z.string(),
		agentName: z.string().optional(),
	}),
	z.object({
		type: z.literal("ssh"),
		name: z.string(),
		host: z.string(),
		port: z.number(),
	}),
	z.object({
		type: z.literal("tcp"),
		name: z.string(),
		host: z.string(),
		port: z.number(),
	}),
	z.object({
		type: z.literal("udp"),
		name: z.string(),
		host: z.string(),
		port: z.number(),
	}),
	z.object({
		type: z.literal("postgresql"),
		name: z.string(),
		host: z.string(),
		port: z.number(),
		database: z.string(),
		username: z.string(),
		password: z.string(),
	}),
	z.object({
		type: z.literal("mongodb"),
		name: z.string(),
		host: z.string(),
		port: z.number(),
		database: z.string(),
		username: z.string(),
		password: z.string(),
	}),
	z.object({
		type: z.literal("env_var"),
		name: z.string(),
		var: z.string(),
	}),
]);

export const DeployResponseSchema = z.object({
	id: z.string(),
	deployKey: z.string(),
	access: z.array(accessSchema),
	envVars: z.array(z.object({ name: z.string(), value: z.string() })),
});

export type DeployResponse = z.infer<typeof DeployResponseSchema>;

export class AppManager {
	private baseUrl: string;

	constructor(baseUrl: string = "http://appmanager.hgrz-appmanager.svc.cluster.local") {
		this.baseUrl = baseUrl;
	}

	async deploy(config: unknown): Promise<DeployResponse> {
		const response = await axios.request({
			url: `${this.baseUrl}/api/dodo-app`,
			method: "post",
			data: { config },
		});
		if (response.status !== 200) {
			throw new Error(`Failed to deploy application: ${response.statusText}`);
		}
		const result = DeployResponseSchema.safeParse(response.data);
		if (!result.success) {
			throw new Error(`Invalid deploy response format: ${result.error.message}`);
		}
		return result.data;
	}

	async update(instanceId: string, config: unknown): Promise<DeployResponse> {
		const response = await axios.request({
			url: `${this.baseUrl}/api/dodo-app/${instanceId}`,
			method: "put",
			data: { config },
		});
		if (response.status !== 200) {
			throw new Error(`Failed to update application: ${response.statusText}`);
		}
		const result = DeployResponseSchema.safeParse(response.data);
		if (!result.success) {
			throw new Error(`Invalid update response format: ${result.error.message}`);
		}
		return result.data;
	}

	async getStatus(instanceId: string): Promise<unknown> {
		const response = await axios.request({
			url: `${this.baseUrl}/api/instance/${instanceId}/status`,
			method: "get",
		});
		if (response.status !== 200) {
			throw new Error(`Failed to get application status: ${response.statusText}`);
		}
		return response.data;
	}

	async removeInstance(instanceId: string): Promise<boolean> {
		const response = await axios.request({
			url: `${this.baseUrl}/api/instance/${instanceId}/remove`,
			method: "post",
		});
		return response.status === 200;
	}
}
