const { app, BrowserWindow, ipcMain, dialog } = require("electron");
const path = require("path");
const fs = require("fs");
const { execFileSync } = require("child_process");
const { initStore } = require("./store");
const { TelegramManager } = require("./telegram");
const { Scheduler } = require("./scheduler");
const { TaskRunner } = require("./taskRunner");

let mainWindow;
let store;
let telegram;
let scheduler;
const taskRunners = new Map();

function createWindow() {
  const iconPath = path.join(__dirname, "..", "..", "resources", "icon.png");
  mainWindow = new BrowserWindow({
    width: 1200,
    height: 800,
    icon: iconPath,
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
      contextIsolation: true,
      nodeIntegration: false
    }
  });

  const devUrl = process.env.VITE_DEV_SERVER_URL || "http://127.0.0.1:5173";
  if (app.isPackaged) {
    mainWindow.loadFile(path.join(__dirname, "..", "..", "dist", "index.html"));
  } else {
    mainWindow.loadURL(devUrl);
  }
}

async function bootstrap() {
  store = initStore(app.getPath("userData"));
  telegram = new TelegramManager(store);
  await telegram.init();
  scheduler = new Scheduler(store, telegram);
}

app.whenReady().then(async () => {
  await bootstrap();
  createWindow();

  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

app.on("window-all-closed", () => {
  if (process.platform !== "darwin") app.quit();
});

ipcMain.handle("settings:get", () => store.getSettings());
ipcMain.handle("settings:save", (_event, settings) => store.saveSettings(settings));

ipcMain.handle("accounts:list", () => store.listAccounts());
ipcMain.handle("accounts:resetCooldown", async (_event, accountId) => {
  store.clearAccountCooldown(accountId);
  store.addAccountEvent(accountId, "", "manual_reset", "Cooldown reset by user");
  return { ok: true };
});
ipcMain.handle("accounts:delete", async (_event, accountId) => {
  await telegram.removeAccount(accountId);
  store.deleteAccount(accountId);
  store.addAccountEvent(accountId, "", "delete", "Account deleted by user");
  return { ok: true };
});
ipcMain.handle("db:clear", async () => {
  for (const runner of taskRunners.values()) {
    runner.stop();
  }
  taskRunners.clear();
  const accounts = store.listAccounts();
  for (const account of accounts) {
    await telegram.removeAccount(account.id);
  }
  store.clearAllData();
  return { ok: true };
});
ipcMain.handle("accounts:startLogin", async (_event, payload) => {
  const result = await telegram.startLogin(payload);
  return result;
});
ipcMain.handle("accounts:completeLogin", async (_event, payload) => {
  const result = await telegram.completeLogin(payload);
  return result;
});

ipcMain.handle("accounts:importTdata", async (_event, payload) => {
  const { canceled, filePaths } = await dialog.showOpenDialog({
    title: "Выберите папку tdata",
    properties: ["openDirectory", "multiSelections"]
  });
  if (canceled || !filePaths || !filePaths.length) return { ok: false, canceled: true };

  const platformDir = process.platform === "win32" ? "win" : "mac";
  const binaryName = process.platform === "win32" ? "tgconvertor.exe" : "tgconvertor";
  const devBinary = path.join(__dirname, "..", "..", "resources", "converter", platformDir, binaryName);
  const packagedBinary = path.join(process.resourcesPath, "converter", platformDir, binaryName);
  const binaryPath = app.isPackaged ? packagedBinary : devBinary;

  if (!fs.existsSync(binaryPath)) {
    return { ok: false, error: "Встроенный конвертер не найден. Соберите его через scripts/build-converter.*" };
  }

  const imported = [];
  const failed = [];
  const skipped = [];
  const assignedIds = [];

  for (const chosenPath of filePaths) {
    let tdataPath = chosenPath;
    const tdataCandidate = path.join(tdataPath, "tdata");
    if (fs.existsSync(tdataCandidate) && fs.lstatSync(tdataCandidate).isDirectory()) {
      tdataPath = tdataCandidate;
    }
    if (path.basename(tdataPath) !== "tdata") {
      failed.push({ path: chosenPath, error: "Нужна папка tdata или папка с вложенной tdata." });
      continue;
    }

    let output = "";
    try {
      output = execFileSync(binaryPath, [tdataPath], { encoding: "utf8" });
    } catch (error) {
      failed.push({ path: chosenPath, error: "Не удалось запустить встроенный конвертер tdata." });
      continue;
    }

    const lines = output.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
    const candidate = lines.find((line) => line.length > 50) || lines[lines.length - 1];
    if (!candidate) {
      failed.push({ path: chosenPath, error: "Не удалось получить строку сессии из tdata." });
      continue;
    }

    try {
      const result = await telegram.importTdataSession({
        sessionString: candidate,
        apiId: payload && payload.apiId,
        apiHash: payload && payload.apiHash
      });
      if (!result.ok) {
        if (result.error === "DUPLICATE_ACCOUNT") {
          skipped.push({ path: chosenPath, reason: "Дубликат", accountId: result.accountId });
          if (result.accountId) assignedIds.push(result.accountId);
          continue;
        }
        failed.push({ path: chosenPath, error: result.error || "Ошибка импорта" });
        continue;
      }
      imported.push({ path: chosenPath, accountId: result.accountId });
      if (result.accountId) assignedIds.push(result.accountId);
    } catch (error) {
      failed.push({ path: chosenPath, error: error.message || String(error) });
    }
  }

  if (payload && payload.taskId && assignedIds.length) {
    const task = store.getTask(payload.taskId);
    if (task) {
      const existing = store.listTaskAccounts(payload.taskId).map((row) => row.account_id);
      const merged = Array.from(new Set([...(existing || []), ...assignedIds]));
      store.setTaskAccounts(payload.taskId, merged);
    }
  }

  return { ok: true, imported, skipped, failed };
});

ipcMain.handle("logs:list", (_event, payload) => {
  if (payload && typeof payload === "object") {
    return store.listLogs(payload.limit || 100, payload.taskId);
  }
  return store.listLogs(payload || 100);
});
ipcMain.handle("invites:list", (_event, payload) => {
  if (payload && typeof payload === "object") {
    return store.listInvites(payload.limit || 200, payload.taskId);
  }
  return store.listInvites(payload || 200);
});
ipcMain.handle("logs:clear", (_event, taskId) => {
  store.clearLogs(taskId);
  return { ok: true };
});
ipcMain.handle("invites:clear", (_event, taskId) => {
  store.clearInvites(taskId);
  return { ok: true };
});
ipcMain.handle("queue:clear", (_event, taskId) => {
  store.clearQueue(taskId);
  return { ok: true };
});

ipcMain.handle("tasks:list", () => store.listTasks());
ipcMain.handle("tasks:get", (_event, id) => {
  const task = store.getTask(id);
  if (!task) return null;
  return {
    task,
    competitors: store.listTaskCompetitors(id).map((row) => row.link),
    accountIds: store.listTaskAccounts(id).map((row) => row.account_id)
  };
});
ipcMain.handle("tasks:save", (_event, payload) => {
  const taskId = store.saveTask(payload.task);
  store.setTaskCompetitors(taskId, payload.competitors || []);
  store.setTaskAccounts(taskId, payload.accountIds || []);
  return { ok: true, taskId };
});
ipcMain.handle("tasks:delete", (_event, id) => {
  const runner = taskRunners.get(id);
  if (runner) {
    runner.stop();
    taskRunners.delete(id);
  }
  store.deleteTask(id);
  return { ok: true };
});
ipcMain.handle("tasks:start", async (_event, id) => {
  const task = store.getTask(id);
  if (!task) return { ok: false, error: "Task not found" };
  let runner = taskRunners.get(id);
  if (!runner) {
    runner = new TaskRunner(store, telegram, task);
    taskRunners.set(id, runner);
  } else {
    runner.task = task;
  }
  await runner.start();
  return { ok: true };
});
ipcMain.handle("tasks:stop", (_event, id) => {
  const runner = taskRunners.get(id);
  if (runner) {
    runner.stop();
    taskRunners.delete(id);
  }
  return { ok: true };
});
ipcMain.handle("tasks:accountAssignments", () => {
  return store.listAllTaskAccounts();
});
ipcMain.handle("tasks:appendAccounts", (_event, payload) => {
  if (!payload || !payload.taskId) return { ok: false, error: "Task not found" };
  const task = store.getTask(payload.taskId);
  if (!task) return { ok: false, error: "Task not found" };
  const existing = store.listTaskAccounts(payload.taskId).map((row) => row.account_id);
  const merged = Array.from(new Set([...(existing || []), ...((payload.accountIds || []))]));
  store.setTaskAccounts(payload.taskId, merged);
  return { ok: true, accountIds: merged };
});
ipcMain.handle("tasks:removeAccount", (_event, payload) => {
  if (!payload || !payload.taskId || !payload.accountId) {
    return { ok: false, error: "Task not found" };
  }
  const task = store.getTask(payload.taskId);
  if (!task) return { ok: false, error: "Task not found" };
  const existing = store.listTaskAccounts(payload.taskId).map((row) => row.account_id);
  const filtered = existing.filter((id) => id !== payload.accountId);
  store.setTaskAccounts(payload.taskId, filtered);
  return { ok: true, accountIds: filtered };
});
ipcMain.handle("tasks:startAll", async () => {
  const tasks = store.listTasks();
  let started = 0;
  let skipped = 0;
  const errors = [];
  for (const task of tasks) {
    if (!task.enabled) {
      skipped += 1;
      continue;
    }
    let runner = taskRunners.get(task.id);
    if (!runner) {
      runner = new TaskRunner(store, telegram, task);
      taskRunners.set(task.id, runner);
    } else {
      runner.task = task;
    }
    try {
      await runner.start();
      started += 1;
    } catch (error) {
      errors.push({ id: task.id, error: error.message || String(error) });
    }
  }
  return { ok: errors.length === 0, started, skipped, errors };
});
ipcMain.handle("tasks:stopAll", () => {
  let stopped = 0;
  for (const [id, runner] of taskRunners.entries()) {
    runner.stop();
    taskRunners.delete(id);
    stopped += 1;
  }
  return { ok: true, stopped };
});
ipcMain.handle("tasks:status", (_event, id) => {
  const runner = taskRunners.get(id);
  const queueCount = store.getPendingCount(id);
  const dailyUsed = store.countInvitesToday(id);
  const task = store.getTask(id);
  const monitorInfo = telegram.getTaskMonitorInfo(id);
  return {
    running: runner ? runner.isRunning() : false,
    queueCount,
    dailyUsed,
    dailyLimit: task ? task.daily_limit : 0,
    dailyRemaining: task ? Math.max(0, Number(task.daily_limit || 0) - dailyUsed) : 0,
    monitorInfo
  };
});

ipcMain.handle("tasks:parseHistory", async (_event, id) => {
  const task = store.getTask(id);
  if (!task) return { ok: false, error: "Task not found" };
  const competitors = store.listTaskCompetitors(id).map((row) => row.link);
  const accounts = store.listTaskAccounts(id).map((row) => row.account_id);
  return telegram.parseHistoryForTask(task, competitors, accounts);
});

ipcMain.handle("tasks:checkAccess", async (_event, id) => {
  const task = store.getTask(id);
  if (!task) return { ok: false, error: "Task not found" };
  const competitors = store.listTaskCompetitors(id).map((row) => row.link);
  return telegram.checkGroupAccess(competitors, task.our_group);
});

ipcMain.handle("tasks:membershipStatus", async (_event, id) => {
  const task = store.getTask(id);
  if (!task) return { ok: false, error: "Task not found" };
  const competitors = store.listTaskCompetitors(id).map((row) => row.link);
  return telegram.getMembershipStatus(competitors, task.our_group);
});

const toCsv = (rows, headers) => {
  const escape = (value) => {
    const text = value == null ? "" : String(value);
    if (text.includes("\"") || text.includes(",") || text.includes("\n")) {
      return `"${text.replace(/\"/g, "\"\"")}"`;
    }
    return text;
  };
  const lines = [headers.join(",")];
  rows.forEach((row) => {
    lines.push(headers.map((key) => escape(row[key])).join(","));
  });
  return lines.join("\n");
};

ipcMain.handle("logs:export", async (_event, taskId) => {
  const { canceled, filePath } = await dialog.showSaveDialog({
    title: "Выгрузить логи",
    defaultPath: "logs.csv"
  });
  if (canceled || !filePath) return { ok: false, canceled: true };

  const logs = store.listLogs(1000, taskId).map((log) => ({
    taskId: log.taskId,
    startedAt: log.startedAt,
    finishedAt: log.finishedAt,
    invitedCount: log.invitedCount,
    successIds: JSON.stringify(log.successIds || []),
    errors: JSON.stringify(log.errors || [])
  }));
  const csv = toCsv(logs, ["taskId", "startedAt", "finishedAt", "invitedCount", "successIds", "errors"]);
  fs.writeFileSync(filePath, csv, "utf8");
  return { ok: true, filePath };
});

ipcMain.handle("invites:export", async (_event, taskId) => {
  const { canceled, filePath } = await dialog.showSaveDialog({
    title: "Выгрузить историю инвайтов",
    defaultPath: "invites.csv"
  });
  if (canceled || !filePath) return { ok: false, canceled: true };

  const invites = store.listInvites(2000, taskId);
  const csv = toCsv(invites, ["taskId", "invitedAt", "userId", "username", "status", "error"]);
  fs.writeFileSync(filePath, csv, "utf8");
  return { ok: true, filePath };
});

ipcMain.handle("accounts:events", async (_event, limit) => {
  return store.listAccountEvents(limit || 200);
});

ipcMain.handle("accounts:refreshIdentity", async () => {
  const accounts = store.listAccounts();
  for (const account of accounts) {
    await telegram.refreshAccountIdentity(account.id);
  }
  return { ok: true };
});

ipcMain.handle("task:start", async () => {
  const settings = store.getSettings();
  if (settings.autoJoinOurGroup) {
    await telegram.ensureJoinOurGroup(settings.ourGroup);
  }
  await telegram.joinGroupsForAllAccounts(settings.competitorGroups, settings.ourGroup, settings);
  const monitorResult = await telegram.startMonitoring(settings.competitorGroups);
  scheduler.start(settings);
  return { running: true, monitorErrors: monitorResult && monitorResult.errors ? monitorResult.errors : [] };
});

ipcMain.handle("task:stop", async () => {
  scheduler.stop();
  await telegram.stopMonitoring();
  return { running: false };
});

ipcMain.handle("status:get", () => {
  const settings = store.getSettings();
  const dailyUsed = store.countInvitesToday();
  const dailyRemaining = Math.max(0, Number(settings.dailyLimit || 0) - dailyUsed);
  const queueCount = store.getPendingCount();
  const accounts = store.listAccounts();
  const accountStats = accounts.map((account) => {
    const used = store.countInvitesTodayByAccount(account.id);
    const limit = Number(account.daily_limit || settings.accountDailyLimit || 0);
    const remaining = limit > 0 ? Math.max(0, limit - used) : null;
    return {
      id: account.id,
      usedToday: used,
      remainingToday: remaining,
      limit
    };
  });
  const monitorInfo = telegram.getMonitorInfo();
  return {
    running: scheduler ? scheduler.isRunning() : false,
    queueCount,
    dailyRemaining,
    dailyUsed,
    dailyLimit: Number(settings.dailyLimit || 0),
    accountStats,
    monitorInfo
  };
});

ipcMain.handle("task:parseHistory", async (_event, limit) => {
  const settings = store.getSettings();
  const result = await telegram.parseHistory(settings.competitorGroups, limit || settings.historyLimit);
  return result;
});

ipcMain.handle("accounts:membershipStatus", async () => {
  const settings = store.getSettings();
  const result = await telegram.getMembershipStatus(settings.competitorGroups, settings.ourGroup);
  return result;
});

ipcMain.handle("groups:checkAccess", async () => {
  const settings = store.getSettings();
  const result = await telegram.checkGroupAccess(settings.competitorGroups, settings.ourGroup);
  return result;
});
