'use client';

import { useEffect, useRef } from 'react';
import type { ScheduledTask } from '../../lib/types';
import { shouldRunNow } from '../../lib/cron';
import { updateScheduledTask } from '../../lib/db';

interface TaskRunnerProps {
  tasks: ScheduledTask[];
  onTaskRan: (taskId: string) => void;
}

export function TaskRunner({ tasks, onTaskRan }: TaskRunnerProps) {
  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);

  useEffect(() => {
    const check = async () => {
      for (const task of tasks) {
        if (!task.enabled) continue;
        if (!shouldRunNow(task.schedule, task.lastRun)) continue;

        const start = Date.now();
        try {
          let input = '';

          if (task.inputSource?.type === 'command') {
            const parts = task.inputSource.command.split(/\s+/);
            const command = parts[0];
            const args = parts.slice(1);
            const res = await fetch('/api/system/exec', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ command, args }),
            });
            const data = (await res.json()) as { stdout?: string; stderr?: string };
            input = data.stdout || data.stderr || '';
          } else if (task.inputSource?.type === 'clipboard') {
            try {
              input = await navigator.clipboard.readText();
            } catch {
              input = '[clipboard unavailable]';
            }
          }

          const finalPrompt = task.prompt.replace(/\{input\}/g, input);

          const res = await fetch('/api/ollama/chat', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
              model: task.model || undefined,
              messages: [{ role: 'user', content: finalPrompt }],
            }),
          });

          let result = '';
          if (res.ok && res.body) {
            const reader = res.body.getReader();
            const decoder = new TextDecoder();
            let buffer = '';
            while (true) {
              const { done, value } = await reader.read();
              if (done) break;
              buffer += decoder.decode(value, { stream: true });
              const lines = buffer.split('\n');
              buffer = lines.pop() || '';
              for (const line of lines) {
                if (!line.trim()) continue;
                try {
                  const chunk = JSON.parse(line) as { message?: { content?: string } };
                  if (chunk.message?.content) result += chunk.message.content;
                } catch {
                  /* skip */
                }
              }
            }
          }

          const durationMs = Date.now() - start;
          const runEntry = {
            timestamp: Date.now(),
            durationMs,
            success: true,
            result: result.slice(0, 500),
          };

          await updateScheduledTask(task.id, {
            lastRun: Date.now(),
            runHistory: [...(task.runHistory || []).slice(-19), runEntry],
          });

          if (task.outputAction?.type === 'notification' && 'Notification' in window) {
            if (Notification.permission === 'granted') {
              new Notification(task.name, { body: result.slice(0, 200) });
            } else if (Notification.permission !== 'denied') {
              await Notification.requestPermission();
            }
          } else if (task.outputAction?.type === 'clipboard') {
            await navigator.clipboard.writeText(result);
          }

          onTaskRan(task.id);
        } catch (err) {
          const durationMs = Date.now() - start;
          const runEntry = {
            timestamp: Date.now(),
            durationMs,
            success: false,
            result: String(err).slice(0, 500),
          };

          await updateScheduledTask(task.id, {
            lastRun: Date.now(),
            runHistory: [...(task.runHistory || []).slice(-19), runEntry],
          });

          onTaskRan(task.id);
        }
      }
    };

    intervalRef.current = setInterval(() => void check(), 60_000);
    return () => {
      if (intervalRef.current) clearInterval(intervalRef.current);
    };
  }, [tasks, onTaskRan]);

  return null;
}
