import chalk from "chalk";
import {
  LinearAuthManager
} from "../../integrations/linear/auth.js";
import { LinearOAuthServer } from "../../integrations/linear/oauth-server.js";
import {
  LinearSyncEngine,
  DEFAULT_SYNC_CONFIG
} from "../../integrations/linear/sync.js";
import {
  LinearSyncManager,
  DEFAULT_SYNC_MANAGER_CONFIG
} from "../../integrations/linear/sync-manager.js";
import { LinearConfigManager } from "../../integrations/linear/config.js";
import { LinearTaskManager } from "../../features/tasks/linear-task-manager.js";
import { LinearClient } from "../../integrations/linear/client.js";
import { LinearRestClient } from "../../integrations/linear/rest-client.js";
import Database from "better-sqlite3";
import { join } from "path";
import { existsSync } from "fs";
import { logger } from "../../core/monitoring/logger.js";
import Table from "cli-table3";
function getEnv(key, defaultValue) {
  const value = process.env[key];
  if (value === void 0) {
    if (defaultValue !== void 0) return defaultValue;
    throw new Error(`Environment variable ${key} is required`);
  }
  return value;
}
function getOptionalEnv(key) {
  return process.env[key];
}
function displaySyncResult(result) {
  if (result.success) {
    console.log(chalk.green("\u2713 Sync completed successfully"));
  } else {
    console.log(chalk.yellow("\u26A0 Sync completed with issues"));
  }
  if (result.synced.toLinear > 0 || result.synced.fromLinear > 0 || result.synced.updated > 0) {
    console.log(chalk.cyan("  \u{1F4CA} Summary:"));
    if (result.synced.toLinear > 0) {
      console.log(`    \u2192 Linear: ${result.synced.toLinear} tasks`);
    }
    if (result.synced.fromLinear > 0) {
      console.log(`    \u2190 Linear: ${result.synced.fromLinear} tasks`);
    }
    if (result.synced.updated > 0) {
      console.log(`    \u2194 Updated: ${result.synced.updated} tasks`);
    }
  }
  if (result.conflicts.length > 0) {
    console.log(chalk.yellow(`  \u26A0 Conflicts: ${result.conflicts.length}`));
    result.conflicts.slice(0, 3).forEach((conflict) => {
      console.log(`    - ${conflict.reason}`);
    });
    if (result.conflicts.length > 3) {
      console.log(`    ... and ${result.conflicts.length - 3} more`);
    }
  }
  if (result.errors.length > 0) {
    console.log(chalk.red(`  \u274C Errors: ${result.errors.length}`));
    result.errors.slice(0, 3).forEach((error) => {
      console.log(`    - ${error.substring(0, 80)}`);
    });
    if (result.errors.length > 3) {
      console.log(`    ... and ${result.errors.length - 3} more`);
    }
  }
}
function registerLinearCommands(parent) {
  const linear = parent.command("linear").description("Linear API integration commands");
  linear.command("list").alias("ls").description("List Linear tasks (memory-cached)").option("--limit <n>", "Number of tasks to show", "20").option(
    "--status <status>",
    "Filter by status (backlog, started, completed, etc.)"
  ).option("--my", "Show only tasks assigned to me").option("--cache", "Show cache stats only").option("--refresh", "Force refresh cache").option("--count", "Show count by status only").action(async (options) => {
    try {
      const apiKey = process.env["LINEAR_API_KEY"];
      if (!apiKey) {
        console.log(
          chalk.yellow("\u26A0 Set LINEAR_API_KEY environment variable")
        );
        return;
      }
      const restClient = new LinearRestClient(apiKey);
      if (options.cache) {
        const stats = restClient.getCacheStats();
        console.log(chalk.cyan("\u{1F4CA} Cache Stats:"));
        console.log(`  Size: ${stats.size} tasks`);
        console.log(`  Age: ${Math.round(stats.age / 1e3)}s`);
        console.log(`  Fresh: ${stats.fresh ? "yes" : "no"}`);
        console.log(
          `  Last sync: ${new Date(stats.lastSync).toLocaleString()}`
        );
        return;
      }
      if (options.count) {
        const counts = await restClient.getTaskCounts();
        console.log(chalk.cyan("\u{1F4CA} Task Counts:"));
        Object.entries(counts).sort(([, a], [, b]) => b - a).forEach(([status, count]) => {
          console.log(`  ${status}: ${count}`);
        });
        return;
      }
      let tasks;
      if (options.my) {
        tasks = await restClient.getMyTasks();
      } else if (options.status) {
        tasks = await restClient.getTasksByStatus(options.status);
      } else {
        tasks = await restClient.getAllTasks(options.refresh);
      }
      if (!tasks || tasks.length === 0) {
        console.log(chalk.gray("No tasks found"));
        return;
      }
      const limit = parseInt(options.limit);
      const displayTasks = tasks.slice(0, limit);
      console.log(
        chalk.cyan(
          `
\u{1F4CB} Linear Tasks (${displayTasks.length}/${tasks.length}):`
        )
      );
      displayTasks.forEach((task) => {
        const priority = task.priority ? `P${task.priority}` : "";
        const assignee = task.assignee ? ` @${task.assignee.name}` : "";
        const statusColor = task.state.type === "completed" ? chalk.green : task.state.type === "started" ? chalk.yellow : chalk.gray;
        console.log(`${chalk.blue(task.identifier)} ${task.title}`);
        console.log(
          chalk.gray(
            `  ${statusColor(task.state.name)} ${priority}${assignee}`
          )
        );
      });
      console.log(
        chalk.gray(
          `
${displayTasks.length} shown, ${tasks.length} total tasks`
        )
      );
    } catch (error) {
      console.error(
        chalk.red("Failed to list tasks:"),
        error.message
      );
    }
  });
  linear.command("auth").description("Authenticate with Linear").option("--api-key <key>", "Use API key instead of OAuth").option("--no-browser", "Do not open browser automatically").action(async (options) => {
    try {
      if (options.apiKey) {
        process.env["LINEAR_API_KEY"] = options.apiKey;
        console.log(chalk.green("\u2713 Linear API key set"));
        const client = new LinearClient({ apiKey: options.apiKey });
        const user = await client.getViewer();
        if (user) {
          console.log(
            chalk.cyan(`Connected as: ${user.name} (${user.email})`)
          );
        }
      } else {
        const authManager = new LinearAuthManager(process.cwd());
        const clientId = process.env["LINEAR_CLIENT_ID"];
        const clientSecret = process.env["LINEAR_CLIENT_SECRET"];
        if (!clientId || !clientSecret) {
          console.log(chalk.yellow("\n\u26A0 Linear OAuth app not configured"));
          console.log(chalk.cyan("\n\u{1F4DD} Setup Instructions:"));
          console.log(
            "  1. Create a Linear OAuth app at: https://linear.app/settings/api"
          );
          console.log(
            "  2. Set redirect URI to: http://localhost:3456/auth/linear/callback"
          );
          console.log("  3. Copy your Client ID and Client Secret");
          console.log("  4. Set environment variables:");
          console.log(
            chalk.gray('     export LINEAR_CLIENT_ID="your_client_id"')
          );
          console.log(
            chalk.gray(
              '     export LINEAR_CLIENT_SECRET="your_client_secret"'
            )
          );
          console.log("  5. Run this command again");
          return;
        }
        authManager.saveConfig({
          clientId,
          clientSecret,
          redirectUri: "http://localhost:3456/auth/linear/callback",
          scopes: ["read", "write", "admin"]
        });
        const oauthServer = new LinearOAuthServer(process.cwd());
        const { url } = await oauthServer.start();
        if (options.browser !== false) {
          const open = (await import("open")).default;
          await open(url);
          console.log(
            chalk.green("\n\u2713 Browser opened with authorization page")
          );
        } else {
          console.log(chalk.cyan("\n\u{1F517} Open this URL in your browser:"));
          console.log(chalk.underline(url));
        }
        console.log(chalk.gray("\nWaiting for authorization..."));
        console.log(
          chalk.gray(
            "The server will automatically shut down after authorization."
          )
        );
      }
    } catch (error) {
      console.error(
        chalk.red("Authentication failed:"),
        error.message
      );
      process.exit(1);
    }
  });
  linear.command("sync").description("Sync tasks with Linear").option(
    "-d, --direction <dir>",
    "Sync direction: bidirectional, to_linear, from_linear",
    "bidirectional"
  ).option("-t, --team <id>", "Default Linear team ID").option("--dry-run", "Preview sync without making changes").option("--daemon", "Run in daemon mode with periodic sync").option(
    "-i, --interval <minutes>",
    "Sync interval in minutes (default: 15)"
  ).action(async (options) => {
    try {
      const projectRoot = process.cwd();
      const dbPath = join(projectRoot, ".stackmemory", "context.db");
      if (!existsSync(dbPath)) {
        console.log(chalk.red("\u274C StackMemory not initialized"));
        return;
      }
      const db = new Database(dbPath);
      const taskStore = new LinearTaskManager(projectRoot, db);
      const authManager = new LinearAuthManager(projectRoot);
      const config = {
        ...DEFAULT_SYNC_CONFIG,
        direction: options.direction,
        defaultTeamId: options.team,
        enabled: true
      };
      if (options.daemon) {
        const managerConfig = {
          ...DEFAULT_SYNC_MANAGER_CONFIG,
          ...config,
          autoSyncInterval: parseInt(options.interval) || 15
        };
        const syncManager = new LinearSyncManager(
          taskStore,
          authManager,
          managerConfig,
          projectRoot
        );
        console.log(chalk.green("\u{1F680} Starting Linear sync daemon"));
        console.log(
          chalk.cyan(
            `  Sync interval: ${managerConfig.autoSyncInterval} minutes`
          )
        );
        console.log(chalk.cyan(`  Direction: ${managerConfig.direction}`));
        console.log(chalk.gray("  Press Ctrl+C to stop\n"));
        const initialResult = await syncManager.syncOnStart();
        if (initialResult) {
          displaySyncResult(initialResult);
        }
        syncManager.on("sync:started", ({ trigger }) => {
          console.log(
            chalk.yellow(
              `
\u{1F504} ${(/* @__PURE__ */ new Date()).toLocaleTimeString()} - Starting ${trigger} sync...`
            )
          );
        });
        syncManager.on("sync:completed", ({ result }) => {
          displaySyncResult(result);
        });
        syncManager.on("sync:failed", ({ result }) => {
          console.log(chalk.red("\u274C Sync failed"));
          if (result.errors.length > 0) {
            result.errors.forEach((error) => {
              console.log(chalk.red(`  - ${error}`));
            });
          }
        });
        process.on("SIGINT", async () => {
          console.log(chalk.yellow("\n\u23F9 Stopping sync daemon..."));
          await syncManager.syncOnEnd();
          syncManager.stop();
          db.close();
          process.exit(0);
        });
        process.stdin.resume();
      } else {
        const syncEngine = new LinearSyncEngine(
          taskStore,
          authManager,
          config
        );
        console.log(chalk.yellow("\u{1F504} Syncing with Linear..."));
        if (options.dryRun) {
          console.log(chalk.gray("(Dry run - no changes will be made)"));
        }
        const result = await syncEngine.sync();
        displaySyncResult(result);
        db.close();
      }
    } catch (error) {
      logger.error("Sync failed", error);
      console.error(chalk.red("Sync failed:"), error.message);
      process.exit(1);
    }
  });
  linear.command("status").description("Show Linear sync status").action(async () => {
    try {
      const authManager = new LinearAuthManager(process.cwd());
      const tokens = authManager.loadTokens();
      const apiKey = process.env["LINEAR_API_KEY"];
      if (!tokens && !apiKey) {
        console.log(chalk.yellow("\u26A0 Not authenticated with Linear"));
        console.log('Run "stackmemory linear auth" to connect');
        return;
      }
      const client = apiKey ? new LinearClient({ apiKey }) : new LinearClient({
        apiKey: tokens.accessToken,
        useBearer: true,
        onUnauthorized: async () => {
          const refreshed = await authManager.refreshAccessToken();
          return refreshed.accessToken;
        }
      });
      const user = await client.getViewer();
      if (user) {
        console.log(chalk.green("\u2713 Connected to Linear"));
        console.log(chalk.cyan(`  User: ${user.name} (${user.email})`));
        const teams = await client.getTeams();
        if (teams && teams.length > 0) {
          console.log(chalk.cyan("\n\u{1F4CB} Teams:"));
          teams.forEach((team) => {
            console.log(`  - ${team.name} (${team.key})`);
          });
        }
      } else {
        console.log(chalk.red("\u274C Could not connect to Linear"));
      }
    } catch (error) {
      console.error(
        chalk.red("Status check failed:"),
        error.message
      );
    }
  });
  linear.command("tasks").description("List Linear tasks").option("--limit <n>", "Number of tasks to show", "50").option(
    "--status <status>",
    "Filter by status (backlog, started, completed, etc.)"
  ).option("--my", "Show only tasks assigned to me").option("--cache", "Show cache stats").option("--refresh", "Force refresh cache").action(async (options) => {
    try {
      const apiKey = process.env["LINEAR_API_KEY"];
      if (!apiKey) {
        console.log(
          chalk.yellow("\u26A0 Set LINEAR_API_KEY environment variable")
        );
        return;
      }
      const restClient = new LinearRestClient(apiKey);
      if (options.cache) {
        const stats = restClient.getCacheStats();
        console.log(chalk.cyan("\u{1F4CA} Cache Stats:"));
        console.log(`  Size: ${stats.size} tasks`);
        console.log(`  Age: ${Math.round(stats.age / 1e3)}s`);
        console.log(`  Fresh: ${stats.fresh ? "yes" : "no"}`);
        console.log(
          `  Last sync: ${new Date(stats.lastSync).toLocaleString()}`
        );
        return;
      }
      let tasks;
      if (options.my) {
        tasks = await restClient.getMyTasks();
      } else if (options.status) {
        tasks = await restClient.getTasksByStatus(options.status);
      } else {
        tasks = await restClient.getAllTasks(options.refresh);
      }
      if (!tasks || tasks.length === 0) {
        console.log(chalk.gray("No tasks found"));
        return;
      }
      const limit = parseInt(options.limit);
      const displayTasks = tasks.slice(0, limit);
      const table = new Table({
        head: ["ID", "Title", "State", "Priority", "Assignee"],
        style: { head: ["cyan"] }
      });
      displayTasks.forEach((task) => {
        table.push([
          task.identifier,
          task.title.substring(0, 40) + (task.title.length > 40 ? "..." : ""),
          task.state?.name || "-",
          task.priority ? `P${task.priority}` : "-",
          task.assignee?.name || "-"
        ]);
      });
      console.log(table.toString());
      const counts = await restClient.getTaskCounts();
      console.log(chalk.cyan("\n\u{1F4CA} Task Summary:"));
      Object.entries(counts).forEach(([status, count]) => {
        console.log(`  ${status}: ${count}`);
      });
      console.log(
        chalk.gray(
          `
Showing ${displayTasks.length} of ${tasks.length} total tasks`
        )
      );
      const cacheStats = restClient.getCacheStats();
      console.log(
        chalk.gray(
          `Cache: ${cacheStats.size} tasks, age: ${Math.round(cacheStats.age / 1e3)}s`
        )
      );
    } catch (error) {
      console.error(
        chalk.red("Failed to list tasks:"),
        error.message
      );
    }
  });
  linear.command("update <issueId>").description("Update Linear task status").option(
    "-s, --status <status>",
    "New status (todo, in-progress, done, canceled)"
  ).option("-t, --title <title>", "Update task title").option("-d, --description <desc>", "Update task description").option(
    "-p, --priority <priority>",
    "Set priority (1=urgent, 2=high, 3=medium, 4=low)"
  ).action(async (issueId, options) => {
    try {
      const authManager = new LinearAuthManager(process.cwd());
      const tokens = authManager.loadTokens();
      if (!tokens) {
        console.error(
          chalk.red("Not authenticated. Run: stackmemory linear auth")
        );
        return;
      }
      const client = new LinearClient({
        apiKey: tokens.accessToken
      });
      let issue = await client.getIssue(issueId);
      if (!issue) {
        issue = await client.findIssueByIdentifier(issueId);
      }
      if (!issue) {
        console.error(chalk.red(`Issue ${issueId} not found`));
        return;
      }
      const updates = {};
      if (options.status) {
        const team = await client.getTeam();
        const states = await client.getWorkflowStates(team.id);
        const statusMap = {
          todo: "unstarted",
          "in-progress": "started",
          done: "completed",
          canceled: "cancelled"
        };
        const targetType = statusMap[options.status.toLowerCase()] || options.status;
        const targetState = states.find((s) => s.type === targetType);
        if (!targetState) {
          console.error(chalk.red(`Invalid status: ${options.status}`));
          console.log(chalk.gray("Available states:"));
          states.forEach(
            (s) => console.log(chalk.gray(`  - ${s.name} (${s.type})`))
          );
          return;
        }
        updates.stateId = targetState.id;
      }
      if (options.title) updates.title = options.title;
      if (options.description) updates.description = options.description;
      if (options.priority) updates.priority = parseInt(options.priority);
      const updatedIssue = await client.updateIssue(issue.id, updates);
      console.log(
        chalk.green(
          `\u2713 Updated ${updatedIssue.identifier}: ${updatedIssue.title}`
        )
      );
      if (options.status) {
        console.log(chalk.cyan(`  Status: ${updatedIssue.state.name}`));
      }
      console.log(chalk.gray(`  ${updatedIssue.url}`));
    } catch (error) {
      console.error(
        chalk.red("Failed to update task:"),
        error.message
      );
    }
  });
  linear.command("config").description("Configure Linear sync settings").option("--team <id>", "Set default team ID").option("--interval <minutes>", "Auto-sync interval in minutes").option("--direction <dir>", "Sync direction").option("--conflict <strategy>", "Conflict resolution strategy").action(async (options) => {
    try {
      const configManager = new LinearConfigManager(process.cwd());
      const config = configManager.loadConfig() || configManager.getDefaultConfig();
      let updated = false;
      if (options.team) {
        logger.info("Team ID configuration not yet implemented", {
          teamId: options.team
        });
      }
      if (options.interval) {
        config.interval = parseInt(options.interval);
        updated = true;
      }
      if (options.direction) {
        config.direction = options.direction;
        updated = true;
      }
      if (options.conflict) {
        config.conflictResolution = options.conflict;
        updated = true;
      }
      if (updated) {
        configManager.saveConfig(config);
        console.log(chalk.green("\u2713 Configuration updated"));
      }
      console.log(chalk.cyan("\n\u{1F4CB} Current Configuration:"));
      console.log(`  Enabled: ${config.enabled ? "yes" : "no"}`);
      console.log(`  Interval: ${config.interval} minutes`);
      console.log(`  Direction: ${config.direction}`);
      console.log(`  Conflicts: ${config.conflictResolution}`);
    } catch (error) {
      console.error(chalk.red("Config failed:"), error.message);
    }
  });
}
export {
  registerLinearCommands
};
//# sourceMappingURL=linear.js.map
