import type { IntegrationProvider, CardData, TestResult, PushResult, ExternalField, JsonValue } from "../types";
import {
  createItem,
  updateItem,
  fetchBoardColumns,
  mapCardToColumnValues,
} from "@/lib/monday";
import { prisma } from "@/lib/db";

interface MondayConfig {
  apiToken: string;
  boardId: string;
  columnMap?: Record<string, unknown>;
}

function parseConfig(config: JsonValue): MondayConfig {
  const c = config as Record<string, unknown>;
  return {
    apiToken: (c.apiToken as string) || "",
    boardId: (c.boardId as string) || "",
    columnMap: (c.columnMap as Record<string, unknown>) || {},
  };
}

export const mondayProvider: IntegrationProvider = {
  id: "monday",
  name: "Monday.com",
  description: "Push response cards to Monday.com boards as items",
  icon: "monday",
  category: "project_mgmt",
  supportsFieldMapping: true,
  supportsOAuth: false,
  configFields: [
    {
      key: "apiToken",
      label: "API Token",
      type: "password",
      required: true,
      helpText: "Found in Monday.com → Admin → API",
    },
    {
      key: "boardId",
      label: "Board ID",
      type: "text",
      required: true,
      helpText: "The numeric board ID from the board URL",
    },
  ],

  setupGuide: {
    summary:
      "Monday.com uses a personal API token for authentication. Generate a token from your Monday account, then paste it here along with the ID of the board you want cards pushed into.",
    docsUrl: "https://developer.monday.com/api-reference/docs/authentication",
    steps: [
      {
        title: "Open Monday.com → Developer Tokens",
        body: "Click your avatar in the bottom-left corner, select \"Developers\", then open the \"My Access Tokens\" tab.",
        linkUrl: "https://monday.com/developers/apps",
        linkLabel: "Open developer console",
      },
      {
        title: "Generate a personal API token",
        body: "Click \"Show\" next to Personal API Token and copy it. This token has access to everything your Monday account can see — treat it like a password.",
      },
      {
        title: "Find the board ID",
        body: "Open the board you want to push cards into. The URL looks like https://yourorg.monday.com/boards/1234567890. The numeric portion at the end is your board ID.",
      },
      {
        title: "Paste the token and board ID into Echo OCR",
        body: "Enter both values below and click Test Connection. If the token is valid, Echo OCR will fetch the board's columns so you can map card fields to columns.",
      },
      {
        title: "Configure column mapping (after connecting)",
        body: "Once connected, open the integration's detail page to map card fields (name, email, phone, etc.) to the matching columns on your board.",
      },
    ],
  },

  async testConnection(config: JsonValue): Promise<TestResult> {
    try {
      const { apiToken, boardId } = parseConfig(config);
      if (!apiToken || !boardId) {
        return { success: false, message: "API token and board ID are required" };
      }
      const columns = await fetchBoardColumns(apiToken, boardId);
      return {
        success: true,
        message: `Connected — found ${columns.length} columns`,
      };
    } catch (err) {
      return {
        success: false,
        message: err instanceof Error ? err.message : "Connection failed",
      };
    }
  },

  async getExternalFields(config: JsonValue): Promise<ExternalField[]> {
    const { apiToken, boardId } = parseConfig(config);
    const columns = await fetchBoardColumns(apiToken, boardId);
    return columns.map((col) => ({
      id: col.id,
      name: col.title,
      type: col.type,
    }));
  },

  async pushCard(
    card: CardData,
    config: JsonValue,
    mapping: JsonValue
  ): Promise<PushResult> {
    try {
      const { apiToken, boardId, columnMap } = parseConfig(config);
      const hasMapping =
        mapping && typeof mapping === "object" && !Array.isArray(mapping) &&
        Object.keys(mapping as Record<string, unknown>).length > 0;
      const effectiveMap = hasMapping
        ? (mapping as Record<string, unknown>)
        : (columnMap || {});
      const cardData = card as unknown as Record<string, unknown>;
      const columnValues = mapCardToColumnValues(cardData, effectiveMap);
      const itemName =
        card.name ||
        [card.firstName, card.lastName].filter(Boolean).join(" ") ||
        "Unnamed Card";

      const existingItemId =
        typeof cardData.mondayItemId === "string" ? cardData.mondayItemId : null;
      const cardId = typeof card.id === "string" ? card.id : null;

      if (existingItemId) {
        await updateItem(apiToken, boardId, existingItemId, columnValues);
        return { success: true, externalId: existingItemId };
      }

      const itemId = await createItem(apiToken, boardId, itemName, columnValues);

      if (cardId) {
        try {
          await prisma.responseCard.update({
            where: { id: cardId },
            data: { mondayItemId: itemId },
          });
        } catch (err) {
          console.error("[monday] Failed to persist mondayItemId:", err);
        }
      }

      return { success: true, externalId: itemId };
    } catch (err) {
      return {
        success: false,
        message: err instanceof Error ? err.message : "Push failed",
      };
    }
  },
};
