export type Schedule =
  | "sunday" | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday"
  | "week" | "day" | "midnight" | "noon" | "hour"
  | "30 minutes" | "15 minutes" | "5 minutes" | "1 minute"
  | "30minutes" | "15minutes" | "5minutes" | "1minute"
  | 30 | 15 | 5 | 1
  | (string & {}) // time strings like "7am", "7:30pm", "14:00"

export type CronJob = {
  id: string              // "appname:filename"
  app: string
  name: string            // filename without .ts
  file: string            // full path
  schedule: Schedule
  cronExpr: string
  state: 'idle' | 'running' | 'disabled'
  lastRun?: number
  lastDuration?: number
  lastExitCode?: number
  lastError?: string
  lastOutput?: string
  nextRun?: number
}

export type InvalidJob = {
  id: string
  app: string
  name: string
  file: string
  error: string
}

export const SCHEDULES = [
  '1 minute',
  '5 minutes',
  '15 minutes',
  '30 minutes',
  'hour',
  'noon',
  'midnight',
  'day',
  'week',
  'sunday',
  'monday',
  'tuesday',
  'wednesday',
  'thursday',
  'friday',
  'saturday',
] as const

const SCHEDULE_MAP: Record<string, string> = {
  sunday: '0 0 * * 0',
  monday: '0 0 * * 1',
  tuesday: '0 0 * * 2',
  wednesday: '0 0 * * 3',
  thursday: '0 0 * * 4',
  friday: '0 0 * * 5',
  saturday: '0 0 * * 6',
  week: '0 0 * * 0',
  day: '0 0 * * *',
  midnight: '0 0 * * *',
  noon: '0 12 * * *',
  hour: '0 * * * *',
  '30 minutes': '0,30 * * * *',
  '15 minutes': '0,15,30,45 * * * *',
  '5 minutes': '*/5 * * * *',
  '1 minute': '* * * * *',
  '30minutes': '0,30 * * * *',
  '15minutes': '0,15,30,45 * * * *',
  '5minutes': '*/5 * * * *',
  '1minute': '* * * * *',
}

export function isValidSchedule(value: unknown): value is Schedule {
  if (typeof value === 'number') {
    return [1, 5, 15, 30].includes(value)
  }
  if (typeof value === 'string') {
    return value in SCHEDULE_MAP || parseTime(value) !== null
  }
  return false
}

function parseTime(s: string): { hour: number, minute: number } | null {
  // 12h: "7am", "7pm", "7:30am", "7:30pm", "12am", "12:00pm"
  const m12 = s.match(/^(\d{1,2})(?::(\d{2}))?\s*(am|pm)$/i)
  if (m12) {
    let hour = parseInt(m12[1]!)
    const minute = m12[2] ? parseInt(m12[2]) : 0
    const period = m12[3]!.toLowerCase()
    if (hour < 1 || hour > 12 || minute > 59) return null
    if (period === 'am' && hour === 12) hour = 0
    else if (period === 'pm' && hour !== 12) hour += 12
    return { hour, minute }
  }

  // 24h: "14:00", "0:00", "23:59"
  const m24 = s.match(/^(\d{1,2}):(\d{2})$/)
  if (m24) {
    const hour = parseInt(m24[1]!)
    const minute = parseInt(m24[2]!)
    if (hour > 23 || minute > 59) return null
    return { hour, minute }
  }

  return null
}

export function toCronExpr(schedule: Schedule): string {
  if (typeof schedule === 'number') {
    return SCHEDULE_MAP[`${schedule}minutes`]!
  }
  if (schedule in SCHEDULE_MAP) {
    return SCHEDULE_MAP[schedule]!
  }
  const time = parseTime(schedule)!
  return `${time.minute} ${time.hour} * * *`
}
