import type { LineChannelData, OpenClawPluginApi, ReplyPayload } from "openclaw/plugin-sdk/line";
import {
  createActionCard,
  createImageCard,
  createInfoCard,
  createListCard,
  createReceiptCard,
  type CardAction,
  type ListItem,
} from "openclaw/plugin-sdk/line";

const CARD_USAGE = `Usage: /card <type> "title" "body" [options]

Types:
  info "Title" "Body" ["Footer"]
  image "Title" "Caption" --url <image-url>
  action "Title" "Body" --actions "Btn1|url1,Btn2|text2"
  list "Title" "Item1|Desc1,Item2|Desc2"
  receipt "Title" "Item1:$10,Item2:$20" --total "$30"
  confirm "Question?" --yes "Yes|data" --no "No|data"
  buttons "Title" "Text" --actions "Btn1|url1,Btn2|data2"

Examples:
  /card info "Welcome" "Thanks for joining!"
  /card image "Product" "Check it out" --url https://example.com/img.jpg
  /card action "Menu" "Choose an option" --actions "Order|/order,Help|/help"`;

function buildLineReply(lineData: LineChannelData): ReplyPayload {
  return {
    channelData: {
      line: lineData,
    },
  };
}

/**
 * Parse action string format: "Label|data,Label2|data2"
 * Data can be a URL (uri action) or plain text (message action) or key=value (postback)
 */
function parseActions(actionsStr: string | undefined): CardAction[] {
  if (!actionsStr) {
    return [];
  }

  const results: CardAction[] = [];

  for (const part of actionsStr.split(",")) {
    const [label, data] = part
      .trim()
      .split("|")
      .map((s) => s.trim());
    if (!label) {
      continue;
    }

    const actionData = data || label;

    if (actionData.startsWith("http://") || actionData.startsWith("https://")) {
      results.push({
        label,
        action: { type: "uri", label: label.slice(0, 20), uri: actionData },
      });
    } else if (actionData.includes("=")) {
      results.push({
        label,
        action: {
          type: "postback",
          label: label.slice(0, 20),
          data: actionData.slice(0, 300),
          displayText: label,
        },
      });
    } else {
      results.push({
        label,
        action: { type: "message", label: label.slice(0, 20), text: actionData },
      });
    }
  }

  return results;
}

/**
 * Parse list items format: "Item1|Subtitle1,Item2|Subtitle2"
 */
function parseListItems(itemsStr: string): ListItem[] {
  return itemsStr
    .split(",")
    .map((part) => {
      const [title, subtitle] = part
        .trim()
        .split("|")
        .map((s) => s.trim());
      return { title: title || "", subtitle };
    })
    .filter((item) => item.title);
}

/**
 * Parse receipt items format: "Item1:$10,Item2:$20"
 */
function parseReceiptItems(itemsStr: string): Array<{ name: string; value: string }> {
  return itemsStr
    .split(",")
    .map((part) => {
      const colonIndex = part.lastIndexOf(":");
      if (colonIndex === -1) {
        return { name: part.trim(), value: "" };
      }
      return {
        name: part.slice(0, colonIndex).trim(),
        value: part.slice(colonIndex + 1).trim(),
      };
    })
    .filter((item) => item.name);
}

/**
 * Parse quoted arguments from command string
 * Supports: /card type "arg1" "arg2" "arg3" --flag value
 */
function parseCardArgs(argsStr: string): {
  type: string;
  args: string[];
  flags: Record<string, string>;
} {
  const result: { type: string; args: string[]; flags: Record<string, string> } = {
    type: "",
    args: [],
    flags: {},
  };

  // Extract type (first word)
  const typeMatch = argsStr.match(/^(\w+)/);
  if (typeMatch) {
    result.type = typeMatch[1].toLowerCase();
    argsStr = argsStr.slice(typeMatch[0].length).trim();
  }

  // Extract quoted arguments
  const quotedRegex = /"([^"]*?)"/g;
  let match;
  while ((match = quotedRegex.exec(argsStr)) !== null) {
    result.args.push(match[1]);
  }

  // Extract flags (--key value or --key "value")
  const flagRegex = /--(\w+)\s+(?:"([^"]*?)"|(\S+))/g;
  while ((match = flagRegex.exec(argsStr)) !== null) {
    result.flags[match[1]] = match[2] ?? match[3];
  }

  return result;
}

export function registerLineCardCommand(api: OpenClawPluginApi): void {
  api.registerCommand({
    name: "card",
    description: "Send a rich card message (LINE).",
    acceptsArgs: true,
    requireAuth: false,
    handler: async (ctx) => {
      const argsStr = ctx.args?.trim() ?? "";
      if (!argsStr) {
        return { text: CARD_USAGE };
      }

      const parsed = parseCardArgs(argsStr);
      const { type, args, flags } = parsed;

      if (!type) {
        return { text: CARD_USAGE };
      }

      // Only LINE supports rich cards; fallback to text elsewhere.
      if (ctx.channel !== "line") {
        const fallbackText = args.join(" - ");
        return { text: `[${type} card] ${fallbackText}`.trim() };
      }

      try {
        switch (type) {
          case "info": {
            const [title = "Info", body = "", footer] = args;
            const bubble = createInfoCard(title, body, footer);
            return buildLineReply({
              flexMessage: {
                altText: `${title}: ${body}`.slice(0, 400),
                contents: bubble,
              },
            });
          }

          case "image": {
            const [title = "Image", caption = ""] = args;
            const imageUrl = flags.url || flags.image;
            if (!imageUrl) {
              return { text: "Error: Image card requires --url <image-url>" };
            }
            const bubble = createImageCard(imageUrl, title, caption);
            return buildLineReply({
              flexMessage: {
                altText: `${title}: ${caption}`.slice(0, 400),
                contents: bubble,
              },
            });
          }

          case "action": {
            const [title = "Actions", body = ""] = args;
            const actions = parseActions(flags.actions);
            if (actions.length === 0) {
              return { text: 'Error: Action card requires --actions "Label1|data1,Label2|data2"' };
            }
            const bubble = createActionCard(title, body, actions, {
              imageUrl: flags.url || flags.image,
            });
            return buildLineReply({
              flexMessage: {
                altText: `${title}: ${body}`.slice(0, 400),
                contents: bubble,
              },
            });
          }

          case "list": {
            const [title = "List", itemsStr = ""] = args;
            const items = parseListItems(itemsStr || flags.items || "");
            if (items.length === 0) {
              return {
                text: 'Error: List card requires items. Usage: /card list "Title" "Item1|Desc1,Item2|Desc2"',
              };
            }
            const bubble = createListCard(title, items);
            return buildLineReply({
              flexMessage: {
                altText: `${title}: ${items.map((i) => i.title).join(", ")}`.slice(0, 400),
                contents: bubble,
              },
            });
          }

          case "receipt": {
            const [title = "Receipt", itemsStr = ""] = args;
            const items = parseReceiptItems(itemsStr || flags.items || "");
            const total = flags.total ? { label: "Total", value: flags.total } : undefined;
            const footer = flags.footer;

            if (items.length === 0) {
              return {
                text: 'Error: Receipt card requires items. Usage: /card receipt "Title" "Item1:$10,Item2:$20" --total "$30"',
              };
            }

            const bubble = createReceiptCard({ title, items, total, footer });
            return buildLineReply({
              flexMessage: {
                altText: `${title}: ${items.map((i) => `${i.name} ${i.value}`).join(", ")}`.slice(
                  0,
                  400,
                ),
                contents: bubble,
              },
            });
          }

          case "confirm": {
            const [question = "Confirm?"] = args;
            const yesStr = flags.yes || "Yes|yes";
            const noStr = flags.no || "No|no";

            const [yesLabel, yesData] = yesStr.split("|").map((s) => s.trim());
            const [noLabel, noData] = noStr.split("|").map((s) => s.trim());

            return buildLineReply({
              templateMessage: {
                type: "confirm",
                text: question,
                confirmLabel: yesLabel || "Yes",
                confirmData: yesData || "yes",
                cancelLabel: noLabel || "No",
                cancelData: noData || "no",
                altText: question,
              },
            });
          }

          case "buttons": {
            const [title = "Menu", text = "Choose an option"] = args;
            const actionsStr = flags.actions || "";
            const actionParts = parseActions(actionsStr);

            if (actionParts.length === 0) {
              return { text: 'Error: Buttons card requires --actions "Label1|data1,Label2|data2"' };
            }

            const templateActions: Array<{
              type: "message" | "uri" | "postback";
              label: string;
              data?: string;
              uri?: string;
            }> = actionParts.map((a) => {
              const action = a.action;
              const label = action.label ?? a.label;
              if (action.type === "uri") {
                return { type: "uri" as const, label, uri: (action as { uri: string }).uri };
              }
              if (action.type === "postback") {
                return {
                  type: "postback" as const,
                  label,
                  data: (action as { data: string }).data,
                };
              }
              return {
                type: "message" as const,
                label,
                data: (action as { text: string }).text,
              };
            });

            return buildLineReply({
              templateMessage: {
                type: "buttons",
                title,
                text,
                thumbnailImageUrl: flags.url || flags.image,
                actions: templateActions,
              },
            });
          }

          default:
            return {
              text: `Unknown card type: "${type}". Available types: info, image, action, list, receipt, confirm, buttons`,
            };
        }
      } catch (err) {
        return { text: `Error creating card: ${String(err)}` };
      }
    },
  });
}
