'use client';

import { useState, useMemo, useCallback } from 'react';
import { motion } from 'framer-motion';
import Link from 'next/link';
import {
  ArrowLeft, Clock, Copy, Check, Play, CalendarDays, RotateCcw, Sparkles
} from 'lucide-react';

/* ------------------------------------------------------------------ */
/*  Cron field definitions                                             */
/* ------------------------------------------------------------------ */

interface FieldDef {
  label: string;
  key: string;
  min: number;
  max: number;
  options: { value: string; label: string }[];
}

const PRESETS: { label: string; cron: string }[] = [
  { label: 'Every minute', cron: '* * * * *' },
  { label: 'Every hour', cron: '0 * * * *' },
  { label: 'Every day at midnight', cron: '0 0 * * *' },
  { label: 'Every Monday at 9 AM', cron: '0 9 * * 1' },
  { label: 'Every 1st of month', cron: '0 0 1 * *' },
  { label: 'Weekdays at 8:30 AM', cron: '30 8 * * 1-5' },
  { label: 'Every 15 minutes', cron: '*/15 * * * *' },
  { label: 'Twice daily (9 AM, 5 PM)', cron: '0 9,17 * * *' },
];

const MONTHS = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
const DAYS_OF_WEEK = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];

function buildFieldDefs(): FieldDef[] {
  return [
    {
      label: 'Minute',
      key: 'minute',
      min: 0,
      max: 59,
      options: [
        { value: '*', label: 'Every minute' },
        ...Array.from({ length: 60 }, (_, i) => ({ value: String(i), label: String(i) })),
      ],
    },
    {
      label: 'Hour',
      key: 'hour',
      min: 0,
      max: 23,
      options: [
        { value: '*', label: 'Every hour' },
        ...Array.from({ length: 24 }, (_, i) => ({
          value: String(i),
          label: `${i === 0 ? '12' : i > 12 ? String(i - 12) : String(i)} ${i < 12 ? 'AM' : 'PM'}`,
        })),
      ],
    },
    {
      label: 'Day of Month',
      key: 'dom',
      min: 1,
      max: 31,
      options: [
        { value: '*', label: 'Every day' },
        ...Array.from({ length: 31 }, (_, i) => ({ value: String(i + 1), label: String(i + 1) })),
      ],
    },
    {
      label: 'Month',
      key: 'month',
      min: 1,
      max: 12,
      options: [
        { value: '*', label: 'Every month' },
        ...MONTHS.map((m, i) => ({ value: String(i + 1), label: m })),
      ],
    },
    {
      label: 'Day of Week',
      key: 'dow',
      min: 0,
      max: 6,
      options: [
        { value: '*', label: 'Every day' },
        ...DAYS_OF_WEEK.map((d, i) => ({ value: String(i), label: d })),
      ],
    },
  ];
}

/* ------------------------------------------------------------------ */
/*  Human-readable translator                                          */
/* ------------------------------------------------------------------ */

function cronToHuman(cron: string): string {
  const parts = cron.trim().split(/\s+/);
  if (parts.length !== 5) return 'Invalid cron expression';
  const [min, hour, dom, month, dow] = parts;

  const segments: string[] = [];

  // Frequency
  if (min === '*' && hour === '*') {
    segments.push('Every minute');
  } else if (min.startsWith('*/')) {
    segments.push(`Every ${min.slice(2)} minutes`);
  } else if (hour === '*') {
    segments.push(`At minute ${min} of every hour`);
  } else if (hour.startsWith('*/')) {
    const m = min === '0' ? '' : ` at minute ${min}`;
    segments.push(`Every ${hour.slice(2)} hours${m}`);
  } else if (hour.includes(',')) {
    const hours = hour.split(',').map(h => formatHour(parseInt(h)));
    segments.push(`At ${min === '0' ? '' : `minute ${min} past `}${hours.join(' and ')}`);
  } else {
    const h = parseInt(hour);
    const m = parseInt(min);
    segments.push(`At ${formatHour(h)}${m > 0 ? `:${String(m).padStart(2, '0')}` : ''}`);
  }

  // Day of month
  if (dom !== '*') {
    if (dom.includes(',')) {
      segments.push(`on the ${dom.split(',').map(ordinal).join(', ')}`);
    } else if (dom.includes('-')) {
      const [a, b] = dom.split('-');
      segments.push(`on the ${ordinal(a)} through ${ordinal(b)}`);
    } else {
      segments.push(`on the ${ordinal(dom)}`);
    }
  }

  // Month
  if (month !== '*') {
    if (month.includes(',')) {
      segments.push(`in ${month.split(',').map(m => MONTHS[parseInt(m) - 1] || m).join(', ')}`);
    } else {
      segments.push(`in ${MONTHS[parseInt(month) - 1] || month}`);
    }
  }

  // Day of week
  if (dow !== '*') {
    if (dow.includes('-')) {
      const [a, b] = dow.split('-');
      segments.push(`${DAYS_OF_WEEK[parseInt(a)]} through ${DAYS_OF_WEEK[parseInt(b)]}`);
    } else if (dow.includes(',')) {
      segments.push(`on ${dow.split(',').map(d => DAYS_OF_WEEK[parseInt(d)] || d).join(', ')}`);
    } else {
      segments.push(`on ${DAYS_OF_WEEK[parseInt(dow)] || dow}`);
    }
  }

  return segments.join(', ');
}

function formatHour(h: number): string {
  if (h === 0) return '12:00 AM';
  if (h === 12) return '12:00 PM';
  return h > 12 ? `${h - 12}:00 PM` : `${h}:00 AM`;
}

function ordinal(n: string): string {
  const num = parseInt(n);
  const s = ['th', 'st', 'nd', 'rd'];
  const v = num % 100;
  return num + (s[(v - 20) % 10] || s[v] || s[0]);
}

/* ------------------------------------------------------------------ */
/*  Next runs calculator                                               */
/* ------------------------------------------------------------------ */

function getNextRuns(cron: string, count: number = 5): Date[] {
  const parts = cron.trim().split(/\s+/);
  if (parts.length !== 5) return [];
  const [minExpr, hourExpr, domExpr, monthExpr, dowExpr] = parts;

  const runs: Date[] = [];
  const now = new Date();
  const cursor = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes() + 1, 0, 0);

  const maxIterations = 525600; // 1 year of minutes
  let iterations = 0;

  while (runs.length < count && iterations < maxIterations) {
    if (
      matchField(cursor.getMinutes(), minExpr) &&
      matchField(cursor.getHours(), hourExpr) &&
      matchField(cursor.getDate(), domExpr) &&
      matchField(cursor.getMonth() + 1, monthExpr) &&
      matchField(cursor.getDay(), dowExpr)
    ) {
      runs.push(new Date(cursor));
    }
    cursor.setMinutes(cursor.getMinutes() + 1);
    iterations++;
  }

  return runs;
}

function matchField(value: number, expr: string): boolean {
  if (expr === '*') return true;
  // Handle step: */n
  if (expr.startsWith('*/')) {
    const step = parseInt(expr.slice(2));
    return value % step === 0;
  }
  // Handle range: a-b
  if (expr.includes('-') && !expr.includes(',')) {
    const [a, b] = expr.split('-').map(Number);
    return value >= a && value <= b;
  }
  // Handle list: a,b,c
  if (expr.includes(',')) {
    return expr.split(',').some(v => {
      if (v.includes('-')) {
        const [a, b] = v.split('-').map(Number);
        return value >= a && value <= b;
      }
      return parseInt(v) === value;
    });
  }
  return parseInt(expr) === value;
}

/* ------------------------------------------------------------------ */
/*  Component                                                          */
/* ------------------------------------------------------------------ */

export default function CRONarchyPage() {
  const fields = useMemo(() => buildFieldDefs(), []);
  const [values, setValues] = useState<Record<string, string>>({
    minute: '0', hour: '9', dom: '*', month: '*', dow: '1-5',
  });
  const [copied, setCopied] = useState(false);
  const [rawMode, setRawMode] = useState(false);
  const [rawInput, setRawInput] = useState('');

  const cronExpression = useMemo(
    () => `${values.minute} ${values.hour} ${values.dom} ${values.month} ${values.dow}`,
    [values]
  );

  const displayCron = rawMode ? rawInput : cronExpression;
  const humanReadable = useMemo(() => cronToHuman(displayCron), [displayCron]);
  const nextRuns = useMemo(() => getNextRuns(displayCron), [displayCron]);

  const handleFieldChange = useCallback((key: string, value: string) => {
    setValues(prev => ({ ...prev, [key]: value }));
    setRawMode(false);
  }, []);

  const handleCopy = useCallback(() => {
    navigator.clipboard.writeText(displayCron);
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  }, [displayCron]);

  const handlePreset = useCallback((cron: string) => {
    const [min, hour, dom, month, dow] = cron.split(' ');
    setValues({ minute: min, hour, dom, month, dow });
    setRawMode(false);
  }, []);

  const handleReset = useCallback(() => {
    setValues({ minute: '*', hour: '*', dom: '*', month: '*', dow: '*' });
    setRawMode(false);
    setRawInput('');
  }, []);

  return (
    <main className="min-h-screen bg-[#0C1222]">
      <div className="max-w-4xl mx-auto px-6 py-8">
        {/* Back */}
        <Link href="/demos" className="inline-flex items-center gap-2 text-gray-500 hover:text-gray-300 text-sm mb-8 transition-colors">
          <ArrowLeft className="w-4 h-4" /> Back to Demos
        </Link>

        {/* Header */}
        <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} className="mb-10">
          <div className="flex items-center gap-3 mb-3">
            <div className="w-10 h-10 rounded-xl bg-emerald-500/10 border border-emerald-500/20 flex items-center justify-center">
              <Clock className="w-5 h-5 text-emerald-400" />
            </div>
            <div>
              <h1 className="text-2xl font-bold text-white">CRONarchy</h1>
              <p className="text-gray-500 text-sm">Visual cron expression builder</p>
            </div>
          </div>
        </motion.div>

        {/* Live Expression Display */}
        <motion.div
          initial={{ opacity: 0, y: 10 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ delay: 0.1 }}
          className="mb-8"
        >
          <div className="bg-black/40 border border-slate-800 rounded-xl p-6">
            <div className="flex items-center justify-between mb-3">
              <span className="text-xs text-gray-500 uppercase tracking-wider">Cron Expression</span>
              <div className="flex gap-2">
                <button
                  onClick={handleReset}
                  className="p-1.5 rounded-lg hover:bg-white/5 text-gray-500 hover:text-gray-300 transition-colors"
                  title="Reset"
                >
                  <RotateCcw className="w-4 h-4" />
                </button>
                <button
                  onClick={handleCopy}
                  className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg bg-sky-500/10 hover:bg-sky-500/20 text-sky-400 text-xs transition-colors"
                >
                  {copied ? <Check className="w-3 h-3" /> : <Copy className="w-3 h-3" />}
                  {copied ? 'Copied!' : 'Copy'}
                </button>
              </div>
            </div>
            <div className="font-mono text-3xl md:text-4xl text-white tracking-wider text-center py-4">
              {displayCron}
            </div>
            <div className="flex items-center justify-center gap-2 mt-3">
              <Sparkles className="w-4 h-4 text-emerald-400" />
              <p className="text-emerald-400 text-sm font-medium">{humanReadable}</p>
            </div>
          </div>
        </motion.div>

        <div className="grid md:grid-cols-2 gap-6">
          {/* Left: Field Selectors */}
          <motion.div initial={{ opacity: 0, x: -10 }} animate={{ opacity: 1, x: 0 }} transition={{ delay: 0.2 }}>
            <div className="bg-white/[0.02] border border-slate-800/50 rounded-xl p-6">
              <h2 className="text-sm font-semibold text-white mb-4 flex items-center gap-2">
                <CalendarDays className="w-4 h-4 text-sky-400" /> Schedule Builder
              </h2>
              <div className="space-y-4">
                {fields.map((field) => (
                  <div key={field.key}>
                    <label className="text-xs text-gray-400 mb-1.5 block">{field.label}</label>
                    <div className="flex gap-2">
                      <select
                        value={values[field.key]}
                        onChange={(e) => handleFieldChange(field.key, e.target.value)}
                        className="flex-1 bg-black/30 border border-slate-700 rounded-lg px-3 py-2 text-sm text-white focus:border-sky-500 focus:outline-none transition-colors appearance-none"
                      >
                        {field.options.map((opt) => (
                          <option key={opt.value} value={opt.value} className="bg-gray-900">
                            {opt.label}
                          </option>
                        ))}
                      </select>
                      <input
                        type="text"
                        value={values[field.key]}
                        onChange={(e) => handleFieldChange(field.key, e.target.value)}
                        className="w-20 bg-black/30 border border-slate-700 rounded-lg px-3 py-2 text-sm text-white font-mono text-center focus:border-sky-500 focus:outline-none transition-colors"
                        placeholder="*"
                      />
                    </div>
                  </div>
                ))}
              </div>

              {/* Raw input */}
              <div className="mt-6 pt-4 border-t border-slate-800/50">
                <label className="text-xs text-gray-400 mb-1.5 block">Or paste a cron expression</label>
                <input
                  type="text"
                  value={rawInput}
                  onChange={(e) => {
                    setRawInput(e.target.value);
                    setRawMode(true);
                    const p = e.target.value.trim().split(/\s+/);
                    if (p.length === 5) {
                      setValues({ minute: p[0], hour: p[1], dom: p[2], month: p[3], dow: p[4] });
                    }
                  }}
                  placeholder="* * * * *"
                  className="w-full bg-black/30 border border-slate-700 rounded-lg px-3 py-2 text-sm text-white font-mono focus:border-sky-500 focus:outline-none transition-colors"
                />
              </div>
            </div>
          </motion.div>

          {/* Right: Presets + Next Runs */}
          <motion.div initial={{ opacity: 0, x: 10 }} animate={{ opacity: 1, x: 0 }} transition={{ delay: 0.3 }} className="space-y-6">
            {/* Presets */}
            <div className="bg-white/[0.02] border border-slate-800/50 rounded-xl p-6">
              <h2 className="text-sm font-semibold text-white mb-4">Quick Presets</h2>
              <div className="grid grid-cols-2 gap-2">
                {PRESETS.map((preset) => (
                  <button
                    key={preset.cron}
                    onClick={() => handlePreset(preset.cron)}
                    className={`text-left px-3 py-2 rounded-lg border text-xs transition-all ${
                      cronExpression === preset.cron
                        ? 'bg-sky-500/10 border-sky-500/30 text-sky-400'
                        : 'bg-black/20 border-slate-800/50 text-gray-400 hover:bg-white/[0.03] hover:text-gray-300'
                    }`}
                  >
                    <div className="font-medium">{preset.label}</div>
                    <div className="font-mono text-[10px] text-gray-600 mt-0.5">{preset.cron}</div>
                  </button>
                ))}
              </div>
            </div>

            {/* Next Runs */}
            <div className="bg-white/[0.02] border border-slate-800/50 rounded-xl p-6">
              <h2 className="text-sm font-semibold text-white mb-4 flex items-center gap-2">
                <Play className="w-4 h-4 text-emerald-400" /> Next 5 Runs
              </h2>
              {nextRuns.length > 0 ? (
                <div className="space-y-2">
                  {nextRuns.map((run, i) => (
                    <div
                      key={i}
                      className="flex items-center gap-3 px-3 py-2 rounded-lg bg-black/20 border border-slate-800/30"
                    >
                      <span className="text-xs text-gray-600 w-5">{i + 1}.</span>
                      <span className="text-sm text-white font-mono">
                        {run.toLocaleDateString('en-US', {
                          weekday: 'short', month: 'short', day: 'numeric', year: 'numeric',
                        })}
                      </span>
                      <span className="text-sm text-sky-400 font-mono ml-auto">
                        {run.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' })}
                      </span>
                    </div>
                  ))}
                </div>
              ) : (
                <p className="text-gray-500 text-sm">No runs found in the next year.</p>
              )}
            </div>
          </motion.div>
        </div>

        {/* Syntax Reference */}
        <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} transition={{ delay: 0.4 }} className="mt-8">
          <div className="bg-white/[0.02] border border-slate-800/50 rounded-xl p-6">
            <h2 className="text-sm font-semibold text-white mb-4">Cron Syntax Reference</h2>
            <div className="grid grid-cols-5 gap-4 text-center">
              {['Minute', 'Hour', 'Day (Month)', 'Month', 'Day (Week)'].map((label, i) => (
                <div key={label}>
                  <div className="text-xs text-gray-500 mb-1">{label}</div>
                  <div className="text-lg font-mono text-sky-400">{displayCron.split(' ')[i] || '*'}</div>
                  <div className="text-[10px] text-gray-600 mt-1">
                    {['0-59', '0-23', '1-31', '1-12', '0-6'][i]}
                  </div>
                </div>
              ))}
            </div>
            <div className="mt-4 pt-4 border-t border-slate-800/50 grid grid-cols-2 md:grid-cols-4 gap-3 text-xs text-gray-500">
              <div><code className="text-sky-400/70">*</code> — any value</div>
              <div><code className="text-sky-400/70">5,10</code> — list</div>
              <div><code className="text-sky-400/70">1-5</code> — range</div>
              <div><code className="text-sky-400/70">*/15</code> — step</div>
            </div>
          </div>
        </motion.div>

        {/* Footer */}
        <div className="text-center mt-10 text-gray-700 text-xs">
          Built by The Hearth • <Link href="/demos" className="text-sky-500/50 hover:text-sky-400">View all demos</Link>
        </div>
      </div>
    </main>
  );
}
