/**
 * <folk-schedule-app> — schedule management UI.
 *
 * Job list with create/edit forms, execution log viewer,
 * and manual run triggers. REST-based (no Automerge client sync).
 */

interface JobData {
	id: string;
	name: string;
	description: string;
	enabled: boolean;
	cronExpression: string;
	cronHuman?: string;
	timezone: string;
	actionType: string;
	actionConfig: Record<string, unknown>;
	lastRunAt: number | null;
	lastRunStatus: "success" | "error" | null;
	lastRunMessage: string;
	nextRunAt: number | null;
	runCount: number;
	createdBy: string;
	createdAt: number;
	updatedAt: number;
}

interface LogEntry {
	id: string;
	jobId: string;
	status: "success" | "error";
	message: string;
	durationMs: number;
	timestamp: number;
}

interface ReminderData {
	id: string;
	title: string;
	description: string;
	remindAt: number;
	allDay: boolean;
	timezone: string;
	notifyEmail: string | null;
	notified: boolean;
	completed: boolean;
	sourceModule: string | null;
	sourceLabel: string | null;
	sourceColor: string | null;
	cronExpression: string | null;
	createdAt: number;
	updatedAt: number;
}

const ACTION_TYPES = [
	{ value: "email", label: "Email" },
	{ value: "webhook", label: "Webhook" },
	{ value: "calendar-event", label: "Calendar Event" },
	{ value: "broadcast", label: "Broadcast" },
	{ value: "backlog-briefing", label: "Backlog Briefing" },
	{ value: "calendar-reminder", label: "Calendar Reminder" },
];

const CRON_PRESETS = [
	{ label: "Every minute", value: "* * * * *" },
	{ label: "Every 5 minutes", value: "*/5 * * * *" },
	{ label: "Hourly", value: "0 * * * *" },
	{ label: "Daily at 9am", value: "0 9 * * *" },
	{ label: "Weekday mornings", value: "0 9 * * 1-5" },
	{ label: "Weekly (Monday 9am)", value: "0 9 * * 1" },
	{ label: "Monthly (1st at 9am)", value: "0 9 1 * *" },
	{ label: "Custom", value: "" },
];

class FolkScheduleApp extends HTMLElement {
	private shadow: ShadowRoot;
	private space = "";
	private jobs: JobData[] = [];
	private log: LogEntry[] = [];
	private reminders: ReminderData[] = [];
	private view: "jobs" | "log" | "form" | "reminders" | "reminder-form" = "jobs";
	private editingJob: JobData | null = null;
	private editingReminder: ReminderData | null = null;
	private loading = false;
	private runningJobId: string | null = null;

	// Reminder form state
	private rFormTitle = "";
	private rFormDescription = "";
	private rFormDate = "";
	private rFormTime = "09:00";
	private rFormAllDay = true;
	private rFormEmail = "";
	private rFormSyncCal = true;

	// Form state
	private formName = "";
	private formDescription = "";
	private formCron = "0 9 * * 1-5";
	private formTimezone = "America/Vancouver";
	private formActionType = "email";
	private formEnabled = true;
	private formConfig: Record<string, string> = {};

	constructor() {
		super();
		this.shadow = this.attachShadow({ mode: "open" });
	}

	connectedCallback() {
		this.space = this.getAttribute("space") || "demo";
		this.loadJobs();
	}

	private getApiBase(): string {
		const path = window.location.pathname;
		const match = path.match(/^(\/[^/]+)?\/rschedule/);
		return match ? match[0] : "";
	}

	private async loadJobs() {
		this.loading = true;
		this.render();
		try {
			const base = this.getApiBase();
			const res = await fetch(`${base}/api/jobs`);
			if (res.ok) {
				const data = await res.json();
				this.jobs = data.results || [];
			}
		} catch { this.jobs = []; }
		this.loading = false;
		this.render();
	}

	private async loadLog() {
		try {
			const base = this.getApiBase();
			const res = await fetch(`${base}/api/log`);
			if (res.ok) {
				const data = await res.json();
				this.log = data.results || [];
			}
		} catch { this.log = []; }
		this.render();
	}

	private async loadReminders() {
		try {
			const base = this.getApiBase();
			const res = await fetch(`${base}/api/reminders`);
			if (res.ok) {
				const data = await res.json();
				this.reminders = data.results || [];
			}
		} catch { this.reminders = []; }
		this.render();
	}

	private async completeReminder(id: string) {
		const base = this.getApiBase();
		await fetch(`${base}/api/reminders/${id}/complete`, { method: "POST" });
		await this.loadReminders();
	}

	private async deleteReminder(id: string) {
		if (!confirm("Delete this reminder?")) return;
		const base = this.getApiBase();
		await fetch(`${base}/api/reminders/${id}`, { method: "DELETE" });
		await this.loadReminders();
	}

	private async snoozeReminder(id: string) {
		const base = this.getApiBase();
		await fetch(`${base}/api/reminders/${id}/snooze`, {
			method: "POST",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({ hours: 24 }),
		});
		await this.loadReminders();
	}

	private async submitReminderForm() {
		const base = this.getApiBase();
		const remindAt = this.rFormAllDay
			? new Date(this.rFormDate + "T09:00:00").getTime()
			: new Date(this.rFormDate + "T" + this.rFormTime).getTime();

		const payload: Record<string, unknown> = {
			title: this.rFormTitle,
			description: this.rFormDescription,
			remindAt,
			allDay: this.rFormAllDay,
			notifyEmail: this.rFormEmail || null,
			syncToCalendar: this.rFormSyncCal,
		};

		const isEdit = !!this.editingReminder;
		const url = isEdit ? `${base}/api/reminders/${this.editingReminder!.id}` : `${base}/api/reminders`;
		const method = isEdit ? "PUT" : "POST";

		const res = await fetch(url, {
			method,
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify(payload),
		});

		if (!res.ok) {
			const err = await res.json().catch(() => ({ error: "Request failed" }));
			alert(err.error || "Failed to save reminder");
			return;
		}

		this.view = "reminders";
		this.editingReminder = null;
		await this.loadReminders();
	}

	private openCreateReminderForm() {
		this.editingReminder = null;
		this.rFormTitle = "";
		this.rFormDescription = "";
		this.rFormDate = new Date().toISOString().slice(0, 10);
		this.rFormTime = "09:00";
		this.rFormAllDay = true;
		this.rFormEmail = "";
		this.rFormSyncCal = true;
		this.view = "reminder-form";
		this.render();
	}

	private openEditReminderForm(r: ReminderData) {
		this.editingReminder = r;
		const d = new Date(r.remindAt);
		this.rFormTitle = r.title;
		this.rFormDescription = r.description;
		this.rFormDate = d.toISOString().slice(0, 10);
		this.rFormTime = `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
		this.rFormAllDay = r.allDay;
		this.rFormEmail = r.notifyEmail || "";
		this.rFormSyncCal = true;
		this.view = "reminder-form";
		this.render();
	}

	private async toggleJob(id: string, enabled: boolean) {
		const base = this.getApiBase();
		await fetch(`${base}/api/jobs/${id}`, {
			method: "PUT",
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify({ enabled }),
		});
		await this.loadJobs();
	}

	private async deleteJob(id: string) {
		if (!confirm("Delete this scheduled job?")) return;
		const base = this.getApiBase();
		await fetch(`${base}/api/jobs/${id}`, { method: "DELETE" });
		await this.loadJobs();
	}

	private async runJob(id: string) {
		this.runningJobId = id;
		this.render();
		const base = this.getApiBase();
		try {
			const res = await fetch(`${base}/api/jobs/${id}/run`, { method: "POST" });
			const result = await res.json();
			alert(result.success ? `Success: ${result.message}` : `Error: ${result.message}`);
		} catch (e: any) {
			alert(`Run failed: ${e.message}`);
		}
		this.runningJobId = null;
		await this.loadJobs();
	}

	private async submitForm() {
		const base = this.getApiBase();
		const payload: Record<string, unknown> = {
			name: this.formName,
			description: this.formDescription,
			cronExpression: this.formCron,
			timezone: this.formTimezone,
			actionType: this.formActionType,
			actionConfig: { ...this.formConfig },
			enabled: this.formEnabled,
		};

		const isEdit = !!this.editingJob;
		const url = isEdit ? `${base}/api/jobs/${this.editingJob!.id}` : `${base}/api/jobs`;
		const method = isEdit ? "PUT" : "POST";

		const res = await fetch(url, {
			method,
			headers: { "Content-Type": "application/json" },
			body: JSON.stringify(payload),
		});

		if (!res.ok) {
			const err = await res.json().catch(() => ({ error: "Request failed" }));
			alert(err.error || "Failed to save job");
			return;
		}

		this.view = "jobs";
		this.editingJob = null;
		await this.loadJobs();
	}

	private openCreateForm() {
		this.editingJob = null;
		this.formName = "";
		this.formDescription = "";
		this.formCron = "0 9 * * 1-5";
		this.formTimezone = "America/Vancouver";
		this.formActionType = "email";
		this.formEnabled = true;
		this.formConfig = {};
		this.view = "form";
		this.render();
	}

	private openEditForm(job: JobData) {
		this.editingJob = job;
		this.formName = job.name;
		this.formDescription = job.description;
		this.formCron = job.cronExpression;
		this.formTimezone = job.timezone;
		this.formActionType = job.actionType;
		this.formEnabled = job.enabled;
		this.formConfig = {};
		if (job.actionConfig) {
			for (const [k, v] of Object.entries(job.actionConfig)) {
				this.formConfig[k] = String(v);
			}
		}
		this.view = "form";
		this.render();
	}

	private formatTime(ts: number | null): string {
		if (!ts) return "—";
		const d = new Date(ts);
		const now = Date.now();
		const diff = now - ts;

		if (diff < 60_000) return "just now";
		if (diff < 3600_000) return `${Math.floor(diff / 60_000)}m ago`;
		if (diff < 86400_000) return `${Math.floor(diff / 3600_000)}h ago`;

		return d.toLocaleDateString("en-US", { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
	}

	private formatFuture(ts: number | null): string {
		if (!ts) return "—";
		const diff = ts - Date.now();
		if (diff < 0) return "overdue";
		if (diff < 60_000) return "< 1m";
		if (diff < 3600_000) return `in ${Math.floor(diff / 60_000)}m`;
		if (diff < 86400_000) return `in ${Math.floor(diff / 3600_000)}h`;
		return `in ${Math.floor(diff / 86400_000)}d`;
	}

	private renderActionConfigFields(): string {
		switch (this.formActionType) {
			case "email":
				return `
					<label class="s-label">To <input type="email" class="s-input" data-config="to" value="${this.esc(this.formConfig.to || "")}" placeholder="user@example.com"></label>
					<label class="s-label">Subject <input type="text" class="s-input" data-config="subject" value="${this.esc(this.formConfig.subject || "")}" placeholder="[rSchedule] {{jobName}}"></label>
					<label class="s-label">Body (HTML) <textarea class="s-input s-textarea" data-config="bodyTemplate" placeholder="<p>Hello from {{jobName}}</p>">${this.esc(this.formConfig.bodyTemplate || "")}</textarea></label>
				`;
			case "webhook":
				return `
					<label class="s-label">URL <input type="url" class="s-input" data-config="url" value="${this.esc(this.formConfig.url || "")}" placeholder="https://example.com/webhook"></label>
					<label class="s-label">Method
						<select class="s-input" data-config="method">
							<option value="POST" ${this.formConfig.method === "POST" || !this.formConfig.method ? "selected" : ""}>POST</option>
							<option value="GET" ${this.formConfig.method === "GET" ? "selected" : ""}>GET</option>
							<option value="PUT" ${this.formConfig.method === "PUT" ? "selected" : ""}>PUT</option>
						</select>
					</label>
					<label class="s-label">Body Template <textarea class="s-input s-textarea" data-config="bodyTemplate" placeholder='{"job":"{{jobName}}","ts":"{{timestamp}}"}'>${this.esc(this.formConfig.bodyTemplate || "")}</textarea></label>
				`;
			case "calendar-event":
				return `
					<label class="s-label">Event Title <input type="text" class="s-input" data-config="title" value="${this.esc(this.formConfig.title || "")}" placeholder="Recurring meeting"></label>
					<label class="s-label">Duration (minutes) <input type="number" class="s-input" data-config="duration" value="${this.esc(this.formConfig.duration || "60")}" min="5" max="1440"></label>
				`;
			case "broadcast":
				return `
					<label class="s-label">Channel <input type="text" class="s-input" data-config="channel" value="${this.esc(this.formConfig.channel || "")}" placeholder="default"></label>
					<label class="s-label">Message <textarea class="s-input s-textarea" data-config="message" placeholder="Scheduled broadcast">${this.esc(this.formConfig.message || "")}</textarea></label>
				`;
			case "backlog-briefing":
				return `
					<label class="s-label">Mode
						<select class="s-input" data-config="mode">
							<option value="morning" ${this.formConfig.mode === "morning" || !this.formConfig.mode ? "selected" : ""}>Morning</option>
							<option value="weekly" ${this.formConfig.mode === "weekly" ? "selected" : ""}>Weekly</option>
							<option value="monthly" ${this.formConfig.mode === "monthly" ? "selected" : ""}>Monthly</option>
						</select>
					</label>
					<label class="s-label">To <input type="email" class="s-input" data-config="to" value="${this.esc(this.formConfig.to || "")}" placeholder="user@example.com"></label>
				`;
			default:
				return `<p style="color:var(--rs-text-secondary)">No configuration needed for this action type.</p>`;
		}
	}

	private esc(s: string): string {
		return s.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
	}

	private render() {
		const styles = `
			<style>
				:host { display:block; font-family:system-ui,-apple-system,sans-serif; color:var(--rs-text-primary); }
				.s-header { display:flex; align-items:center; justify-content:space-between; margin-bottom:24px; flex-wrap:wrap; gap:12px; }
				.s-title { font-size:1.5rem; font-weight:700; margin:0; }
				.s-tabs { display:flex; gap:4px; background:rgba(30,41,59,0.6); border-radius:8px; padding:3px; }
				.s-tab { padding:6px 16px; border-radius:6px; border:none; background:transparent; color:var(--rs-text-secondary); cursor:pointer; font-size:13px; transition:all 0.15s; }
				.s-tab:hover { color:var(--rs-text-primary); }
				.s-tab.active { background:rgba(245,158,11,0.15); color:#f59e0b; }
				.s-btn { padding:8px 16px; border-radius:8px; border:none; cursor:pointer; font-size:13px; font-weight:600; transition:all 0.15s; }
				.s-btn-primary { background:linear-gradient(135deg,#f59e0b,#f97316); color:#0f172a; }
				.s-btn-primary:hover { opacity:0.9; }
				.s-btn-secondary { background:rgba(51,65,85,0.6); color:var(--rs-text-primary); }
				.s-btn-secondary:hover { background:rgba(71,85,105,0.6); }
				.s-btn-danger { background:rgba(239,68,68,0.15); color:var(--rs-error); }
				.s-btn-danger:hover { background:rgba(239,68,68,0.25); }
				.s-btn-sm { padding:4px 10px; font-size:12px; }
				.s-btn:disabled { opacity:0.5; cursor:not-allowed; }
				.s-table { width:100%; border-collapse:collapse; }
				.s-table th { text-align:left; padding:10px 12px; font-size:11px; text-transform:uppercase; letter-spacing:0.05em; color:var(--rs-text-muted); border-bottom:2px solid var(--rs-bg-surface); }
				.s-table td { padding:10px 12px; border-bottom:1px solid rgba(30,41,59,0.6); font-size:14px; vertical-align:middle; }
				.s-table tr:hover td { background:rgba(30,41,59,0.3); }
				.s-status { display:inline-block; width:8px; height:8px; border-radius:50%; margin-right:6px; }
				.s-status-success { background:var(--rs-success); }
				.s-status-error { background:var(--rs-error); }
				.s-status-null { background:var(--rs-bg-surface-raised); }
				.s-toggle { position:relative; width:36px; height:20px; cursor:pointer; }
				.s-toggle input { opacity:0; width:0; height:0; position:absolute; }
				.s-toggle .slider { position:absolute; inset:0; background:var(--rs-border-strong); border-radius:20px; transition:0.2s; }
				.s-toggle .slider::before { content:''; position:absolute; height:14px; width:14px; left:3px; bottom:3px; background:var(--rs-text-secondary); border-radius:50%; transition:0.2s; }
				.s-toggle input:checked + .slider { background:rgba(245,158,11,0.3); }
				.s-toggle input:checked + .slider::before { transform:translateX(16px); background:#f59e0b; }
				.s-card { background:var(--rs-bg-surface-sunken); border:1px solid rgba(30,41,59,0.8); border-radius:12px; padding:24px; margin-bottom:16px; }
				.s-form-grid { display:grid; grid-template-columns:1fr 1fr; gap:16px; }
				.s-form-full { grid-column:1/-1; }
				.s-label { display:flex; flex-direction:column; gap:6px; font-size:13px; color:var(--rs-text-secondary); font-weight:500; }
				.s-input { padding:8px 12px; background:rgba(30,41,59,0.8); border:1px solid var(--rs-border-strong); border-radius:6px; color:var(--rs-text-primary); font-size:14px; font-family:inherit; }
				.s-input:focus { outline:none; border-color:#f59e0b; }
				.s-textarea { min-height:80px; resize:vertical; }
				.s-actions { display:flex; gap:6px; flex-wrap:wrap; }
				.s-empty { text-align:center; padding:48px 20px; color:var(--rs-text-muted); }
				.s-loading { text-align:center; padding:48px; color:var(--rs-text-secondary); }
				.s-log-item { display:flex; gap:12px; padding:10px 0; border-bottom:1px solid rgba(30,41,59,0.6); font-size:13px; align-items:flex-start; }
				.s-log-time { color:var(--rs-text-muted); white-space:nowrap; min-width:120px; }
				.s-log-msg { color:var(--rs-text-primary); flex:1; word-break:break-word; }
				.s-log-dur { color:var(--rs-text-muted); white-space:nowrap; }
				@media (max-width:768px) {
					.s-form-grid { grid-template-columns:1fr; }
					.s-table { font-size:12px; }
					.s-table th, .s-table td { padding:8px 6px; }
				}
			</style>
		`;

		if (this.loading) {
			this.shadow.innerHTML = `${styles}<div class="s-loading">Loading schedule...</div>`;
			return;
		}

		let content = "";

		if (this.view === "jobs") {
			content = this.renderJobList();
		} else if (this.view === "log") {
			content = this.renderLog();
		} else if (this.view === "form") {
			content = this.renderForm();
		} else if (this.view === "reminders") {
			content = this.renderReminderList();
		} else if (this.view === "reminder-form") {
			content = this.renderReminderForm();
		}

		const activeTab = this.view === "form" ? "jobs" : this.view === "reminder-form" ? "reminders" : this.view;
		let headerAction = "";
		if (this.view === "jobs") headerAction = `<button class="s-btn s-btn-primary" data-action="create">+ New Job</button>`;
		else if (this.view === "reminders") headerAction = `<button class="s-btn s-btn-primary" data-action="create-reminder">+ New Reminder</button>`;

		this.shadow.innerHTML = `
			${styles}
			<div class="s-header">
				<h1 class="s-title">rSchedule</h1>
				<div class="s-tabs">
					<button class="s-tab ${activeTab === "jobs" ? "active" : ""}" data-view="jobs">Jobs</button>
					<button class="s-tab ${activeTab === "reminders" ? "active" : ""}" data-view="reminders">Reminders</button>
					<button class="s-tab ${activeTab === "log" ? "active" : ""}" data-view="log">Execution Log</button>
				</div>
				${headerAction}
			</div>
			${content}
		`;

		this.attachListeners();
	}

	private renderJobList(): string {
		if (this.jobs.length === 0) {
			return `<div class="s-empty"><p>No scheduled jobs yet.</p><p style="margin-top:8px"><button class="s-btn s-btn-primary" data-action="create">Create your first job</button></p></div>`;
		}

		const rows = this.jobs.map((j) => `
			<tr>
				<td>
					<label class="s-toggle">
						<input type="checkbox" ${j.enabled ? "checked" : ""} data-toggle="${j.id}">
						<span class="slider"></span>
					</label>
				</td>
				<td>
					<strong style="color:var(--rs-text-primary)">${this.esc(j.name)}</strong>
					${j.description ? `<br><span style="color:var(--rs-text-muted);font-size:12px">${this.esc(j.description)}</span>` : ""}
				</td>
				<td style="font-family:monospace;font-size:12px;color:var(--rs-text-secondary)" title="${this.esc(j.cronExpression)}">${this.esc(j.cronHuman || j.cronExpression)}</td>
				<td style="color:var(--rs-text-secondary);font-size:13px">${this.esc(j.timezone)}</td>
				<td><span style="background:rgba(245,158,11,0.1);color:#f59e0b;padding:2px 8px;border-radius:4px;font-size:12px">${this.esc(j.actionType)}</span></td>
				<td>
					<span class="s-status s-status-${j.lastRunStatus || "null"}"></span>
					<span style="color:var(--rs-text-secondary);font-size:13px">${this.formatTime(j.lastRunAt)}</span>
				</td>
				<td style="color:var(--rs-text-secondary);font-size:13px">${this.formatFuture(j.nextRunAt)}</td>
				<td>
					<div class="s-actions">
						<button class="s-btn s-btn-secondary s-btn-sm" data-run="${j.id}" ${this.runningJobId === j.id ? "disabled" : ""}>${this.runningJobId === j.id ? "Running..." : "Run Now"}</button>
						<button class="s-btn s-btn-secondary s-btn-sm" data-edit="${j.id}">Edit</button>
						<button class="s-btn s-btn-danger s-btn-sm" data-delete="${j.id}">Delete</button>
					</div>
				</td>
			</tr>
		`).join("");

		return `
			<div style="overflow-x:auto">
				<table class="s-table">
					<thead>
						<tr>
							<th style="width:50px">On</th>
							<th>Job</th>
							<th>Schedule</th>
							<th>Timezone</th>
							<th>Action</th>
							<th>Last Run</th>
							<th>Next Run</th>
							<th style="width:200px">Actions</th>
						</tr>
					</thead>
					<tbody>${rows}</tbody>
				</table>
			</div>
		`;
	}

	private renderLog(): string {
		if (this.log.length === 0) {
			return `<div class="s-empty"><p>No execution log entries yet.</p><p style="color:var(--rs-text-muted);margin-top:8px">Jobs will log their results here after they run.</p></div>`;
		}

		const jobNames = new Map(this.jobs.map((j) => [j.id, j.name]));
		const entries = this.log.map((e) => `
			<div class="s-log-item">
				<span class="s-status s-status-${e.status}" style="margin-top:4px"></span>
				<span class="s-log-time">${new Date(e.timestamp).toLocaleString()}</span>
				<span style="color:#f59e0b;font-weight:500;min-width:140px">${this.esc(jobNames.get(e.jobId) || e.jobId)}</span>
				<span class="s-log-msg">${this.esc(e.message)}</span>
				<span class="s-log-dur">${e.durationMs}ms</span>
			</div>
		`).join("");

		return `<div class="s-card">${entries}</div>`;
	}

	private renderForm(): string {
		const isEdit = !!this.editingJob;
		const presetOptions = CRON_PRESETS.map((p) =>
			`<option value="${p.value}" ${this.formCron === p.value ? "selected" : ""}>${p.label}</option>`
		).join("");

		const actionOptions = ACTION_TYPES.map((a) =>
			`<option value="${a.value}" ${this.formActionType === a.value ? "selected" : ""}>${a.label}</option>`
		).join("");

		return `
			<div class="s-card">
				<h2 style="margin:0 0 20px;font-size:1.1rem">${isEdit ? "Edit Job" : "Create New Job"}</h2>
				<div class="s-form-grid">
					<label class="s-label">Name <input type="text" class="s-input" id="f-name" value="${this.esc(this.formName)}" placeholder="My scheduled job"></label>
					<label class="s-label">
						Enabled
						<label class="s-toggle" style="margin-top:4px">
							<input type="checkbox" id="f-enabled" ${this.formEnabled ? "checked" : ""}>
							<span class="slider"></span>
						</label>
					</label>
					<label class="s-label s-form-full">Description <input type="text" class="s-input" id="f-desc" value="${this.esc(this.formDescription)}" placeholder="What this job does..."></label>
					<label class="s-label">Cron Preset
						<select class="s-input" id="f-preset">${presetOptions}</select>
					</label>
					<label class="s-label">Cron Expression <input type="text" class="s-input" id="f-cron" value="${this.esc(this.formCron)}" placeholder="* * * * *" style="font-family:monospace"></label>
					<label class="s-label">Timezone <input type="text" class="s-input" id="f-tz" value="${this.esc(this.formTimezone)}" placeholder="America/Vancouver"></label>
					<label class="s-label">Action Type
						<select class="s-input" id="f-action">${actionOptions}</select>
					</label>
					<div class="s-form-full" style="border-top:1px solid var(--rs-bg-surface);padding-top:16px;margin-top:8px">
						<h3 style="font-size:14px;color:var(--rs-text-secondary);margin:0 0 12px">Action Configuration</h3>
						<div class="s-form-grid" id="f-config-fields">
							${this.renderActionConfigFields()}
						</div>
					</div>
				</div>
				<div style="display:flex;gap:8px;margin-top:24px">
					<button class="s-btn s-btn-primary" data-action="submit">${isEdit ? "Update Job" : "Create Job"}</button>
					<button class="s-btn s-btn-secondary" data-action="cancel">Cancel</button>
				</div>
			</div>
		`;
	}

	private renderReminderList(): string {
		if (this.reminders.length === 0) {
			return `<div class="s-empty"><p>No reminders yet.</p><p style="margin-top:8px"><button class="s-btn s-btn-primary" data-action="create-reminder">Create your first reminder</button></p></div>`;
		}

		const rows = this.reminders.map((r) => {
			const dateStr = new Date(r.remindAt).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
			const timeStr = r.allDay ? "All day" : new Date(r.remindAt).toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" });
			const statusBadge = r.completed
				? '<span style="background:rgba(34,197,94,0.15);color:#22c55e;padding:2px 8px;border-radius:4px;font-size:12px">Done</span>'
				: r.notified
				? '<span style="background:rgba(59,130,246,0.15);color:#3b82f6;padding:2px 8px;border-radius:4px;font-size:12px">Sent</span>'
				: '<span style="background:rgba(245,158,11,0.15);color:#f59e0b;padding:2px 8px;border-radius:4px;font-size:12px">Pending</span>';

			return `<tr>
				<td>
					<div style="display:flex;align-items:center;gap:8px">
						<span style="width:8px;height:8px;border-radius:50%;background:${r.sourceColor || "#f59e0b"};flex-shrink:0"></span>
						<div>
							<strong style="color:var(--rs-text-primary)">${this.esc(r.title)}</strong>
							${r.description ? `<br><span style="color:var(--rs-text-muted);font-size:12px">${this.esc(r.description.slice(0, 60))}</span>` : ""}
						</div>
					</div>
				</td>
				<td style="color:var(--rs-text-secondary);font-size:13px">${dateStr}<br><span style="font-size:11px;color:var(--rs-text-muted)">${timeStr}</span></td>
				<td>${r.sourceLabel ? `<span style="color:${r.sourceColor || "var(--rs-text-secondary)"};font-size:12px">${this.esc(r.sourceLabel)}</span>` : '<span style="color:var(--rs-text-muted);font-size:12px">Free-form</span>'}</td>
				<td>${statusBadge}</td>
				<td>
					<div class="s-actions">
						${!r.completed ? `<button class="s-btn s-btn-secondary s-btn-sm" data-r-complete="${r.id}">Complete</button>` : ""}
						${!r.completed ? `<button class="s-btn s-btn-secondary s-btn-sm" data-r-snooze="${r.id}">Snooze</button>` : ""}
						<button class="s-btn s-btn-secondary s-btn-sm" data-r-edit="${r.id}">Edit</button>
						<button class="s-btn s-btn-danger s-btn-sm" data-r-delete="${r.id}">Delete</button>
					</div>
				</td>
			</tr>`;
		}).join("");

		return `
			<div style="overflow-x:auto">
				<table class="s-table">
					<thead>
						<tr>
							<th>Reminder</th>
							<th>Date</th>
							<th>Source</th>
							<th>Status</th>
							<th style="width:220px">Actions</th>
						</tr>
					</thead>
					<tbody>${rows}</tbody>
				</table>
			</div>
		`;
	}

	private renderReminderForm(): string {
		const isEdit = !!this.editingReminder;
		return `
			<div class="s-card">
				<h2 style="margin:0 0 20px;font-size:1.1rem">${isEdit ? "Edit Reminder" : "Create New Reminder"}</h2>
				<div class="s-form-grid">
					<label class="s-label s-form-full">Title <input type="text" class="s-input" id="rf-title" value="${this.esc(this.rFormTitle)}" placeholder="Reminder title..."></label>
					<label class="s-label s-form-full">Description <input type="text" class="s-input" id="rf-desc" value="${this.esc(this.rFormDescription)}" placeholder="Optional description..."></label>
					<label class="s-label">Date <input type="date" class="s-input" id="rf-date" value="${this.rFormDate}"></label>
					<label class="s-label">
						All Day
						<label class="s-toggle" style="margin-top:4px">
							<input type="checkbox" id="rf-allday" ${this.rFormAllDay ? "checked" : ""}>
							<span class="slider"></span>
						</label>
					</label>
					${!this.rFormAllDay ? `<label class="s-label">Time <input type="time" class="s-input" id="rf-time" value="${this.rFormTime}"></label>` : ""}
					<label class="s-label">Email Notification <input type="email" class="s-input" id="rf-email" value="${this.esc(this.rFormEmail)}" placeholder="user@example.com (optional)"></label>
					<label class="s-label">
						Sync to Calendar
						<label class="s-toggle" style="margin-top:4px">
							<input type="checkbox" id="rf-sync" ${this.rFormSyncCal ? "checked" : ""}>
							<span class="slider"></span>
						</label>
					</label>
				</div>
				<div style="display:flex;gap:8px;margin-top:24px">
					<button class="s-btn s-btn-primary" data-action="submit-reminder">${isEdit ? "Update Reminder" : "Create Reminder"}</button>
					<button class="s-btn s-btn-secondary" data-action="cancel-reminder">Cancel</button>
				</div>
			</div>
		`;
	}

	private attachListeners() {
		// Tab switching
		this.shadow.querySelectorAll<HTMLButtonElement>("[data-view]").forEach((btn) => {
			btn.addEventListener("click", () => {
				this.view = btn.dataset.view as "jobs" | "log" | "reminders";
				if (this.view === "log") this.loadLog();
				else if (this.view === "reminders") this.loadReminders();
				else this.render();
			});
		});

		// Create button
		this.shadow.querySelectorAll<HTMLButtonElement>("[data-action='create']").forEach((btn) => {
			btn.addEventListener("click", () => this.openCreateForm());
		});

		// Toggle
		this.shadow.querySelectorAll<HTMLInputElement>("[data-toggle]").forEach((input) => {
			input.addEventListener("change", () => {
				this.toggleJob(input.dataset.toggle!, input.checked);
			});
		});

		// Run
		this.shadow.querySelectorAll<HTMLButtonElement>("[data-run]").forEach((btn) => {
			btn.addEventListener("click", () => this.runJob(btn.dataset.run!));
		});

		// Edit
		this.shadow.querySelectorAll<HTMLButtonElement>("[data-edit]").forEach((btn) => {
			btn.addEventListener("click", () => {
				const job = this.jobs.find((j) => j.id === btn.dataset.edit);
				if (job) this.openEditForm(job);
			});
		});

		// Delete
		this.shadow.querySelectorAll<HTMLButtonElement>("[data-delete]").forEach((btn) => {
			btn.addEventListener("click", () => this.deleteJob(btn.dataset.delete!));
		});

		// Form: cancel
		this.shadow.querySelector<HTMLButtonElement>("[data-action='cancel']")?.addEventListener("click", () => {
			this.view = "jobs";
			this.render();
		});

		// Form: submit
		this.shadow.querySelector<HTMLButtonElement>("[data-action='submit']")?.addEventListener("click", () => {
			this.collectFormData();
			this.submitForm();
		});

		// Form: preset selector
		this.shadow.querySelector<HTMLSelectElement>("#f-preset")?.addEventListener("change", (e) => {
			const val = (e.target as HTMLSelectElement).value;
			if (val) {
				this.formCron = val;
				const cronInput = this.shadow.querySelector<HTMLInputElement>("#f-cron");
				if (cronInput) cronInput.value = val;
			}
		});

		// Form: action type change -> re-render config fields
		this.shadow.querySelector<HTMLSelectElement>("#f-action")?.addEventListener("change", (e) => {
			this.collectFormData();
			this.formActionType = (e.target as HTMLSelectElement).value;
			this.formConfig = {}; // reset config for new action type
			const container = this.shadow.querySelector<HTMLDivElement>("#f-config-fields");
			if (container) container.innerHTML = this.renderActionConfigFields();
			this.attachConfigListeners();
		});

		this.attachConfigListeners();

		// Reminder: create button
		this.shadow.querySelectorAll<HTMLButtonElement>("[data-action='create-reminder']").forEach((btn) => {
			btn.addEventListener("click", () => this.openCreateReminderForm());
		});

		// Reminder: complete
		this.shadow.querySelectorAll<HTMLButtonElement>("[data-r-complete]").forEach((btn) => {
			btn.addEventListener("click", () => this.completeReminder(btn.dataset.rComplete!));
		});

		// Reminder: snooze
		this.shadow.querySelectorAll<HTMLButtonElement>("[data-r-snooze]").forEach((btn) => {
			btn.addEventListener("click", () => this.snoozeReminder(btn.dataset.rSnooze!));
		});

		// Reminder: edit
		this.shadow.querySelectorAll<HTMLButtonElement>("[data-r-edit]").forEach((btn) => {
			btn.addEventListener("click", () => {
				const r = this.reminders.find((rem) => rem.id === btn.dataset.rEdit);
				if (r) this.openEditReminderForm(r);
			});
		});

		// Reminder: delete
		this.shadow.querySelectorAll<HTMLButtonElement>("[data-r-delete]").forEach((btn) => {
			btn.addEventListener("click", () => this.deleteReminder(btn.dataset.rDelete!));
		});

		// Reminder form: cancel
		this.shadow.querySelector<HTMLButtonElement>("[data-action='cancel-reminder']")?.addEventListener("click", () => {
			this.view = "reminders";
			this.loadReminders();
		});

		// Reminder form: submit
		this.shadow.querySelector<HTMLButtonElement>("[data-action='submit-reminder']")?.addEventListener("click", () => {
			this.collectReminderFormData();
			this.submitReminderForm();
		});

		// Reminder form: all-day toggle re-renders to show/hide time field
		this.shadow.querySelector<HTMLInputElement>("#rf-allday")?.addEventListener("change", (e) => {
			this.collectReminderFormData();
			this.rFormAllDay = (e.target as HTMLInputElement).checked;
			this.render();
		});
	}

	private attachConfigListeners() {
		this.shadow.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>("[data-config]").forEach((el) => {
			el.addEventListener("input", () => {
				this.formConfig[el.dataset.config!] = el.value;
			});
			el.addEventListener("change", () => {
				this.formConfig[el.dataset.config!] = el.value;
			});
		});
	}

	private collectFormData() {
		const getName = this.shadow.querySelector<HTMLInputElement>("#f-name");
		const getDesc = this.shadow.querySelector<HTMLInputElement>("#f-desc");
		const getCron = this.shadow.querySelector<HTMLInputElement>("#f-cron");
		const getTz = this.shadow.querySelector<HTMLInputElement>("#f-tz");
		const getAction = this.shadow.querySelector<HTMLSelectElement>("#f-action");
		const getEnabled = this.shadow.querySelector<HTMLInputElement>("#f-enabled");

		if (getName) this.formName = getName.value;
		if (getDesc) this.formDescription = getDesc.value;
		if (getCron) this.formCron = getCron.value;
		if (getTz) this.formTimezone = getTz.value;
		if (getAction) this.formActionType = getAction.value;
		if (getEnabled) this.formEnabled = getEnabled.checked;

		// Collect config fields
		this.shadow.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>("[data-config]").forEach((el) => {
			this.formConfig[el.dataset.config!] = el.value;
		});
	}

	private collectReminderFormData() {
		const getTitle = this.shadow.querySelector<HTMLInputElement>("#rf-title");
		const getDesc = this.shadow.querySelector<HTMLInputElement>("#rf-desc");
		const getDate = this.shadow.querySelector<HTMLInputElement>("#rf-date");
		const getTime = this.shadow.querySelector<HTMLInputElement>("#rf-time");
		const getAllDay = this.shadow.querySelector<HTMLInputElement>("#rf-allday");
		const getEmail = this.shadow.querySelector<HTMLInputElement>("#rf-email");
		const getSync = this.shadow.querySelector<HTMLInputElement>("#rf-sync");

		if (getTitle) this.rFormTitle = getTitle.value;
		if (getDesc) this.rFormDescription = getDesc.value;
		if (getDate) this.rFormDate = getDate.value;
		if (getTime) this.rFormTime = getTime.value;
		if (getAllDay) this.rFormAllDay = getAllDay.checked;
		if (getEmail) this.rFormEmail = getEmail.value;
		if (getSync) this.rFormSyncCal = getSync.checked;
	}
}

customElements.define("folk-schedule-app", FolkScheduleApp);
