import { env } from "~/env";
import { GetFlagValueHandler } from "~/server/controllers/flags.controller";
import { db } from "~/server/db";
import { NewMail } from "~/server/services/mailer";

const BASEURL = "https://api.skebby.it/API/v1.0/REST/";

enum MessageType {
	HIGH_QUALITY = "GP",
	MEDIUM_QUALITY = "TI",
	LOW_QUALITY = "SI",
}

interface Auth {
	user_key: string;
	session_key: string;
}

interface SMSData {
	/** The type of SMS */
	message_type: MessageType;
	/** The body of the message. *Message max length could be 160 chars when using low-quality SMSs. New line char needs to be codified as “\n”. */
	message: string;
	/** A list of recipents phone numbers. The recipients’ numbers must be in the international format (+393471234567 or 00393471234567) */
	recipient: string[];
	/** The Sender name. If the message type allows a custom TPOA and the field is left empty, the user’s preferred TPOA is used. Must be empty if the message type does not allow a custom TPOA */
	sender?: string;
	/** The messages will be sent at the given scheduled time
	 * formats: ddMMyy, yyyyMMdd, ddMMyyHHmm, yyyyMMddHHmmss, yyyy-MM-dd HH:mm, yyyy-MM-dd HH:mm.0 */
	scheduled_delivery_time?: string;
	/** IANA time zone: Europe/Rome, America/New_York, etc. */
	scheduled_delivery_timezone?: string;
	/** Specifies a custom order ID
	 * optional, max 32 characters */
	order_id?: string;
	/** Returns the number of used sms credits. */
	returnCredits?: boolean;
	/** Returns the number of remaining SMS credits for the quality used in the sent SMS and for the default user nation */
	returnRemaining?: boolean;
	/** if true, allows sending to invalid recipients */
	allowInvalidRecipients?: boolean;
	/** default is "gsm" */
	encoding?: "gsm" | "ucs2";
	id_landing?: number;
	/** optional, max 64 characters */
	campaign_name?: string;
	/** max number of fragments for the message, default is 7 */
	max_fragments?: number;
	/** if true, truncates the message to fit the max fragments , default is true */
	truncate?: boolean;
	/** Period after which the SMS message will be deleted from the SMS center. */
	validity_period_min?: number;
	richsms_url?: string;
}

export type MinimalSMSData = Omit<SMSData, "message_type" | "sender">;
interface SMSResponse {
	result: unknown; // or "OK" | any if you're less strict
	[key: string]: unknown; // allow additional unknown keys
}

/**
 * Authenticates the user given their username and password.
 */
async function login(username: string, password: string): Promise<Auth> {
	const url = `${BASEURL}login?username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`;
	const response = await fetch(url);

	if (response.status === 401) {
		throw new Error("Authentication failed: Invalid username or password");
	}
	if (response.status === 400) {
		throw new Error(`Error in request: ${await response.text()}`);
	}

	if (!response.ok || response.status !== 200) {
		throw new Error(`Login failed: ${response.status} ${response.statusText}`);
	}

	const text = await response.text();
	const [user_key, session_key] = text.split(";");
	if (!user_key || !session_key) {
		throw new Error("Invalid login response format");
	}
	return { session_key, user_key };
}

/**
 * Sends an SMS message
 */
async function sendSMS(auth: Auth, smsData: SMSData) {
	const url = `${BASEURL}sms`;

	const response = await fetch(url, {
		body: JSON.stringify(smsData),
		headers: {
			"Content-Type": "application/json",
			Session_key: auth.session_key,
			user_key: auth.user_key,
		},
		method: "POST",
	});

	if (response.status === 400) {
		throw new Error(`Invalid input: ${await response.text()}`);
	}
	if (response.status === 401) {
		throw new Error("Authentication failed: Invalid user key or session key");
	}
	if (response.status === 404) {
		throw new Error("Not Found: The User_key was not found");
	}

	if (response.status !== 201) {
		const errorText = await response.text();
		throw new Error(`SMS send failed: ${response.status} ${errorText}`);
	}

	const data = (await response.json()) as SMSResponse;
	if (data.result !== "OK") {
		throw new Error("SMS send returned non-OK result");
	}
}

// Example usage
/*const smsData: SMSData = {
  recipient: ["+393407246729"],
  message: "Hello world!",
  message_type: MessageType.HIGH_QUALITY,
  sender: "InfoAlloggi",
};*/

export const SendMessage = async (data: MinimalSMSData) => {
	const smsFlag = await GetFlagValueHandler({
		db: db,
		id: "SMS_ENABLED",
	});
	if (smsFlag) {
		try {
			const auth = await login(env.SKEBBY_USER, env.SKEBBY_PASS);
			await sendSMS(auth, {
				...data,
				message_type: MessageType.HIGH_QUALITY,
				sender: "InfoAlloggi",
			});
		} catch (error) {
			console.error("Error:", error);

			await NewMail({
				template: {
					mailType: "generic",
					props: {
						testo: `Errore durante l'invio dell'SMS: to:${data.recipient.join(", ")} Mgs:${data.message}; ${error instanceof Error ? error.message : String(error)}`,
						title: "Errore invio SMS",
					},
				},
				mail: {
					subject: "Errore invio SMS",
					to: "web@infoalloggi.it",
				},
			});
		}
	} else {
		console.warn(
			`SMS sending is disabled to:${data.recipient.join(", ")} Mgs:${data.message}`,
		);
		return {
			message: `SMS sending is disabled: to:${data.recipient.join(", ")} Mgs:${data.message}`,
			success: true,
		};
	}
};
