// unifi-wifi-list.ts
import axios, { AxiosInstance } from "axios";

process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";

const controllerBaseUrl = "https://unifi.totaltech.net";
const site = "km9b1v8i";
const username = "admin";
const password = "Tt$Un1fiIZth3B3$t26";

interface WlanConfRaw {
  _id: string;
  name?: string;
  ssid?: string;
  x_passphrase?: string;
  [key: string]: unknown;
}

interface WlanConf {
  id: string;
  ssid: string;
  password: string | null;
}

class UnifiClient {
  private client: AxiosInstance;

  constructor(baseURL: string) {
    this.client = axios.create({
      baseURL,
      validateStatus: (s) => s >= 200 && s < 400,
    });
  }

  private persistSession(res: { headers: Record<string, unknown> }): void {
    // Cookies
    const raw = res.headers["set-cookie"];
    if (raw) {
      const cookies = (Array.isArray(raw) ? raw : [raw]) as string[];
      const cookieString = cookies.map((c) => c.split(";")[0]).join("; ");
      this.client.defaults.headers.common["Cookie"] = cookieString;
    }
    // CSRF token (UniFi OS)
    const csrf = res.headers["x-csrf-token"];
    if (typeof csrf === "string") {
      this.client.defaults.headers.common["X-CSRF-Token"] = csrf;
    }
  }

  async login(username: string, password: string): Promise<void> {
    const body = { username, password };

    try {
      // UniFi OS
      const res = await this.client.post("/api/auth/login", body);
      console.log("Login OK (UniFi OS)", res.status);
      this.persistSession(res);
    } catch (e) {
      // Legacy controller
      console.log("UniFi OS login failed, trying legacy...");
      const res = await this.client.post("/api/login", body);
      console.log("Login OK (legacy)", res.status);
      this.persistSession(res);
    }
  }

  private async fetchWlanConfRaw(site: string): Promise<WlanConfRaw[]> {
    const paths = [
      `/proxy/network/api/s/${site}/rest/wlanconf`,
      `/api/s/${site}/rest/wlanconf`,
    ];

    for (const path of paths) {
      try {
        const res = await this.client.get(path);
        const data = (res.data?.data ?? res.data) as WlanConfRaw[];
        console.log(`Fetched wlan from ${path}`);
        return data;
      } catch (e) {
        console.log(
          `Failed ${path}:`,
          axios.isAxiosError(e) ? e.response?.status : e,
        );
      }
    }

    throw new Error("Could not fetch WLAN config from any known path");
  }

  async getWlanConf(site: string): Promise<WlanConf[]> {
    const raw = await this.fetchWlanConfRaw(site);

    return raw.map(
      (w): WlanConf => ({
        id: w._id,
        ssid: (w.name || w.ssid || "").toString(),
        password: typeof w.x_passphrase === "string" ? w.x_passphrase : null,
      }),
    );
  }
}

async function main() {
  const unifi = new UnifiClient(controllerBaseUrl);

  try {
    await unifi.login(username, password);

    const wlans = await unifi.getWlanConf(site);

    wlans.forEach((wlan) => {
      console.log(`${wlan.ssid}: ${wlan.password ?? "<no password>"}`);
    });
  } catch (err) {
    if (axios.isAxiosError(err)) {
      console.error("HTTP error", err.response?.status, err.response?.data);
    } else {
      console.error("Error", err);
    }
  }
}

main().catch((e) => console.error(e));
