import { command, flag, option, optional, string } from "cmd-ts";
import { note, text, password, confirm, select, spinner, log } from "@clack/prompts";
import { AtpAgent } from "@atproto/api";
import {
  saveCredentials,
  deleteCredentials,
  listCredentials,
  getCredentials,
  getCredentialsPath,
} from "../lib/credentials";
import { resolveHandleToPDS } from "../lib/atproto";
import { exitOnCancel } from "../lib/prompts";

export const authCommand = command({
  name: "auth",
  description: "Authenticate with your ATProto PDS",
  args: {
    logout: option({
      long: "logout",
      description: "Remove credentials for a specific identity (or all if only one exists)",
      type: optional(string),
    }),
    list: flag({
      long: "list",
      description: "List all stored identities",
    }),
  },
  handler: async ({ logout, list }) => {
    // List identities
    if (list) {
      const identities = await listCredentials();
      if (identities.length === 0) {
        log.info("No stored identities");
      } else {
        log.info("Stored identities:");
        for (const id of identities) {
          console.log(`  - ${id}`);
        }
      }
      return;
    }

    // Logout
    if (logout !== undefined) {
      // If --logout was passed without a value, it will be an empty string
      const identifier = logout || undefined;

      if (!identifier) {
        // No identifier provided - show available and prompt
        const identities = await listCredentials();
        if (identities.length === 0) {
          log.info("No saved credentials found");
          return;
        }
        if (identities.length === 1) {
          const deleted = await deleteCredentials(identities[0]);
          if (deleted) {
            log.success(`Removed credentials for ${identities[0]}`);
          }
          return;
        }
        // Multiple identities - prompt
        const selected = exitOnCancel(await select({
          message: "Select identity to remove:",
          options: identities.map(id => ({ value: id, label: id })),
        }));
        const deleted = await deleteCredentials(selected);
        if (deleted) {
          log.success(`Removed credentials for ${selected}`);
        }
        return;
      }

      const deleted = await deleteCredentials(identifier);
      if (deleted) {
        log.success(`Removed credentials for ${identifier}`);
      } else {
        log.info(`No credentials found for ${identifier}`);
      }
      return;
    }

    note(
      "To authenticate, you'll need an App Password.\n\n" +
        "Create one at: https://bsky.app/settings/app-passwords\n\n" +
        "App Passwords are safer than your main password and can be revoked.",
      "Authentication"
    );

    const identifier = exitOnCancel(await text({
      message: "Handle or DID:",
      placeholder: "yourhandle.bsky.social",
    }));

    const appPassword = exitOnCancel(await password({
      message: "App Password:",
    }));

    if (!identifier || !appPassword) {
      log.error("Handle and password are required");
      process.exit(1);
    }

    // Check if this identity already exists
    const existing = await getCredentials(identifier);
    if (existing) {
      const overwrite = exitOnCancel(await confirm({
        message: `Credentials for ${identifier} already exist. Update?`,
        initialValue: false,
      }));
      if (!overwrite) {
        log.info("Keeping existing credentials");
        return;
      }
    }

    // Resolve PDS from handle
    const s = spinner();
    s.start("Resolving PDS...");
    let pdsUrl: string;
    try {
      pdsUrl = await resolveHandleToPDS(identifier);
      s.stop(`Found PDS: ${pdsUrl}`);
    } catch (error) {
      s.stop("Failed to resolve PDS");
      log.error(`Failed to resolve PDS from handle: ${error}`);
      process.exit(1);
    }

    // Verify credentials
    s.start("Verifying credentials...");

    try {
      const agent = new AtpAgent({ service: pdsUrl });
      await agent.login({
        identifier: identifier,
        password: appPassword,
      });

      s.stop(`Logged in as ${agent.session?.handle}`);

      // Save credentials
      await saveCredentials({
        pdsUrl,
        identifier: identifier,
        password: appPassword,
      });

      log.success(`Credentials saved to ${getCredentialsPath()}`);
    } catch (error) {
      s.stop("Failed to login");
      log.error(`Failed to login: ${error}`);
      process.exit(1);
    }
  },
});
