import type { MinionPluginService, MinionPluginServiceContext } from "openclaw/plugin-sdk";
import type { NitterPluginConfig } from "./config.js";
import type { deliverFeedItems } from "./delivery.js";
import type { FeedStateManager } from "./feed-state.js";
import type { fetchNitterRss, NitterRssItem } from "./rss.js";

export type PollerApi = {
  enqueueSystemEvent: (text: string, options: { sessionKey: string; contextKey?: string }) => void;
  logger: {
    info: (msg: string) => void;
    warn: (msg: string) => void;
    error: (msg: string) => void;
  };
};

export type PollerServiceDeps = {
  api: PollerApi;
  config: NitterPluginConfig;
  fetchRss: typeof fetchNitterRss;
  FeedStateManager: typeof import("./feed-state.js").FeedStateManager;
  deliverItems: typeof deliverFeedItems;
};

const STARTUP_DELAY_MS = 10_000;
const TICK_INTERVAL_MS = 30_000;

let activeFeedState: InstanceType<typeof import("./feed-state.js").FeedStateManager> | null = null;

export function getActiveFeedState(): InstanceType<
  typeof import("./feed-state.js").FeedStateManager
> | null {
  return activeFeedState;
}

export function createNitterPollerService(deps: PollerServiceDeps): MinionPluginService {
  let interval: ReturnType<typeof setInterval> | null = null;
  let startupTimeout: ReturnType<typeof setTimeout> | null = null;

  async function pollAllFeeds(
    feedState: InstanceType<typeof import("./feed-state.js").FeedStateManager>,
  ): Promise<void> {
    const subscriptions = feedState.listSubscriptions();

    for (const sub of subscriptions) {
      if (!sub.enabled) continue;

      try {
        const pollState = feedState.getPollState(sub.username);
        const pollIntervalMs = sub.pollIntervalMs ?? deps.config.pollIntervalMs;

        if (Date.now() - pollState.lastPollAtMs < pollIntervalMs) {
          continue;
        }

        const result = await deps.fetchRss({
          instanceUrl: deps.config.instanceUrl,
          username: sub.username,
          maxItems: deps.config.maxItemsPerPoll,
          timeoutMs: deps.config.requestTimeoutMs,
        });

        if (result.ok) {
          const newItems = feedState.recordPoll(sub.username, {
            items: result.items,
          }) as NitterRssItem[];

          if (newItems.length > 0) {
            deps.deliverItems({
              items: newItems,
              subscription: sub,
              config: deps.config,
              api: deps.api,
            });
            deps.api.logger.info(
              `[nitter] @${sub.username}: ${newItems.length} new item(s) delivered`,
            );
          }
        } else {
          feedState.recordPoll(sub.username, { error: result.error });
          deps.api.logger.warn(`[nitter] @${sub.username} poll failed: ${result.error}`);
        }
      } catch (err: unknown) {
        const message = err instanceof Error ? err.message : String(err);
        feedState.recordPoll(sub.username, { error: message });
        deps.api.logger.warn(`[nitter] @${sub.username} poll error: ${message}`);
      }
    }
  }

  return {
    id: "nitter-poller",

    async start(ctx: MinionPluginServiceContext) {
      const feedState = new deps.FeedStateManager(ctx.stateDir);
      await feedState.load();
      feedState.syncFromConfig(deps.config.feeds);
      activeFeedState = feedState;

      startupTimeout = setTimeout(() => {
        startupTimeout = null;

        interval = setInterval(() => {
          void pollAllFeeds(feedState);
        }, TICK_INTERVAL_MS);
        interval.unref?.();

        // Run the first poll immediately after the startup delay
        void pollAllFeeds(feedState);
      }, STARTUP_DELAY_MS);

      startupTimeout.unref?.();
    },

    stop() {
      if (startupTimeout !== null) {
        clearTimeout(startupTimeout);
        startupTimeout = null;
      }
      if (interval !== null) {
        clearInterval(interval);
        interval = null;
      }
      activeFeedState = null;
    },
  };
}
