import React, { useMemo } from "react";
import { __, sprintf } from "@wordpress/i18n";
import { Info } from "lucide-react";

const MIN_CYCLE_DAYS = 3;

const SEGMENTS = [
	{ id: 1, color: "#2e9e4f", label: __("Full amount", "arraysubs") },
	{ id: 2, color: "#2271b1", label: __("Prorate amount", "arraysubs") },
	{ id: 3, color: "#d63638", label: __("Charge full for next billing cycle", "arraysubs") },
];

/** Nominal cycle length, matching SegmentPlan::getNominalCycleDays(). */
export const nominalCycleDays = (period, interval) => {
	const perPeriod = { day: 1, week: 7, month: 30, year: 365 };
	return (perPeriod[period] || 30) * Math.max(1, Number(interval) || 1);
};

const defaultThirds = (days) => {
	const b1 = Math.max(1, Math.floor(days / 3));
	const b2 = Math.max(b1 + 1, Math.floor((days * 2) / 3));
	return [b1, Math.min(b2, days - 1)];
};

/**
 * "Flexible Renewal Sync" step — the box equivalent of the segment plan on
 * simple products. Active segments split the billing cycle and decide how the
 * first payment is charged based on the signup day.
 *
 * The box owns this setting outright: the subscription the customer buys is the
 * box, so the segment plan is read from the box product. Leaving it off does not
 * disable syncing — it hands the box back to the store-wide renewal sync setting
 * (Settings → General → Sync Renewals to Next Billing Cycle). Either way, the
 * renewal-sync settings on the products
 * placed inside the box are never consulted: their child subscriptions inherit
 * the box's dates on every renewal.
 */
const SyncRenewalsBuilder = ({ sync, schedule, onChange }) => {
	const cycleDays = nominalCycleDays(schedule.period, schedule.interval);
	const sliderDays = Math.max(MIN_CYCLE_DAYS, cycleDays);
	const tooShort = cycleDays < MIN_CYCLE_DAYS;

	const actives = useMemo(
		() => SEGMENTS.filter((s) => sync[`seg${s.id}_active`]).map((s) => s.id),
		[sync]
	);

	const boundaries = useMemo(() => {
		const [d1, d2] = defaultThirds(sliderDays);
		const b1 = sync.seg1_end > 0 ? Math.min(sync.seg1_end, sliderDays - 1) : d1;
		const b2 = sync.seg2_end > 0 ? Math.min(sync.seg2_end, sliderDays - 1) : d2;
		if (actives.length === 3) {
			return [Math.min(b1, b2 - 1) || 1, Math.max(b2, b1 + 1)];
		}
		if (actives.length === 2) {
			return [b1];
		}
		return [];
	}, [sync, sliderDays, actives.length]);

	const update = (patch) => onChange({ ...sync, ...patch });

	const setBoundary = (index, rawValue) => {
		const step = 1;
		const lower = index > 0 ? boundaries[index - 1] + step : 1;
		const upper = index < boundaries.length - 1 ? boundaries[index + 1] - step : sliderDays - 1;
		const value = Math.round(Math.min(Math.max(Number(rawValue), lower), Math.max(lower, upper)));
		if (index === 0) {
			update({ seg1_end: value, seg2_end: boundaries[1] || sync.seg2_end });
		} else {
			update({ seg2_end: value });
		}
	};

	const toggleSegment = (id) => {
		const key = `seg${id}_active`;
		const nextActive = !sync[key];
		// At least one segment must stay on.
		if (!nextActive && actives.length === 1) {
			return;
		}
		const next = { ...sync, [key]: nextActive };
		// Redistribute evenly for the new active count.
		const count = SEGMENTS.filter((s) => next[`seg${s.id}_active`]).length;
		if (count === 3) {
			const [d1, d2] = defaultThirds(sliderDays);
			next.seg1_end = d1;
			next.seg2_end = d2;
		} else if (count === 2) {
			next.seg1_end = Math.max(1, Math.floor(sliderDays / 2));
		}
		onChange(next);
	};

	// Day ranges per active segment for the legend.
	const ranges = useMemo(() => {
		const map = {};
		let from = 1;
		actives.forEach((id, i) => {
			const to = i < boundaries.length ? boundaries[i] : sliderDays;
			map[id] = from >= to ? `${to}` : `${from} - ${to}`;
			from = to + 1;
		});
		return map;
	}, [actives, boundaries, sliderDays]);

	const gradient = useMemo(() => {
		if (actives.length === 0) {
			return "#c3c4c7";
		}
		const stops = [];
		let prevPct = 0;
		actives.forEach((id, i) => {
			const to = i < boundaries.length ? boundaries[i] : sliderDays;
			const pct = Math.min(100, (to / sliderDays) * 100);
			const color = SEGMENTS.find((s) => s.id === id).color;
			stops.push(`${color} ${prevPct}% ${pct}%`);
			prevPct = pct;
		});
		return `linear-gradient(to right, ${stops.join(", ")})`;
	}, [actives, boundaries, sliderDays]);

	return (
		<div className="arraysubs-box-sync">
			<div className="arraysubs-box-section">
				<div className="arraysubs-box-section__head">
					<h3 className="arraysubs-box-section__title">
						{__("Flexible Renewal Sync", "arraysubs")}
					</h3>
					<p className="arraysubs-box-section__desc">
						{__(
							"Align every box renewal to the same calendar boundary and choose how the first payment is charged, based on which day of the cycle the customer subscribes.",
							"arraysubs"
						)}
					</p>
				</div>

				<div className="arraysubs-box-alert">
					<Info size={16} className="arraysubs-box-alert__icon" />
					<div className="arraysubs-box-alert__body">
						<strong>
							{__(
								"Renewal sync for this box is always decided here, never by the products inside it.",
								"arraysubs"
							)}
						</strong>
						<ul>
							<li>
								{__(
									"Leave this unchecked and the box follows your store-wide renewal sync setting (Settings → General → Sync Renewals to Next Billing Cycle), exactly like any other subscription product.",
									"arraysubs"
								)}
							</li>
							<li>
								{__(
									"Tick it to give this box its own segment plan. It then applies whether or not store-wide renewal sync is turned on.",
									"arraysubs"
								)}
							</li>
							<li>
								{__(
									"Renewal sync settings on the products added to this box are ignored. The customer buys one subscription — the box — and each included subscription product simply inherits the box's renewal dates.",
									"arraysubs"
								)}
							</li>
						</ul>
					</div>
				</div>

				<label className="arraysubs-box-checkbox">
					<input
						type="checkbox"
						checked={!!sync.enabled}
						onChange={(event) => {
							const enabled = event.target.checked;
							// Seed the boundaries on enable so the saved config
							// carries the same values the slider displays.
							if (enabled && !(sync.seg1_end > 0 && sync.seg2_end > 0)) {
								const [d1, d2] = defaultThirds(sliderDays);
								update({ enabled, seg1_end: d1, seg2_end: d2 });
								return;
							}
							update({ enabled });
						}}
					/>
					<span>
						<strong>
							{__("Give this box its own segment plan", "arraysubs")}
						</strong>
						<span className="arraysubs-box-field__help">
							{__(
								"Leave unchecked to follow the store-wide renewal sync setting. Supported for manual payment gateways and Stripe.",
								"arraysubs"
							)}
						</span>
					</span>
				</label>

				{sync.enabled && tooShort && (
					<div className="arraysubs-box-alert arraysubs-box-alert--warning">
						<Info size={16} className="arraysubs-box-alert__icon" />
						<div className="arraysubs-box-alert__body">
							{__(
								"This billing cycle is too short to split into segments. Renewal sync needs a cycle of at least 3 days.",
								"arraysubs"
							)}
						</div>
					</div>
				)}

				{sync.enabled && !tooShort && (
					<>
						<div className="arraysubs-box-sync__slider">
							<div className="arraysubs-box-sync__bar" style={{ background: gradient }}>
								{boundaries.map((boundary, index) => (
									// eslint-disable-next-line react/no-array-index-key
									<React.Fragment key={index}>
										<input
											type="range"
											className="arraysubs-box-sync__range"
											min={0}
											max={sliderDays}
											step={1}
											value={boundary}
											onChange={(event) => setBoundary(index, event.target.value)}
											aria-label={sprintf(
												/* translators: %d: boundary number. */
												__("End day of active segment %d", "arraysubs"),
												index + 1
											)}
										/>
										<span
											className="arraysubs-box-sync__bubble"
											style={{
												left: `calc(${Math.min(100, (boundary / sliderDays) * 100)}% - ${
													(Math.min(100, (boundary / sliderDays) * 100) / 100) * 18 - 9
												}px)`,
											}}
										>
											{sprintf(
												/* translators: %d: day of the billing cycle. */
												__("Day %d", "arraysubs"),
												boundary
											)}
										</span>
									</React.Fragment>
								))}
							</div>
							<div className="arraysubs-box-sync__scale">
								<span>{__("Day 1", "arraysubs")}</span>
								<span>
									{sprintf(
										/* translators: %d: last day of the billing cycle. */
										__("Day %d", "arraysubs"),
										sliderDays
									)}
								</span>
							</div>
						</div>

						<div className="arraysubs-box-sync__legend">
							{SEGMENTS.map((segment) => {
								const isActive = !!sync[`seg${segment.id}_active`];
								return (
									<div
										key={segment.id}
										className={`arraysubs-box-sync__legend-row${isActive ? "" : " is-inactive"}`}
									>
										<label className="arraysubs-box-switch">
											<input
												type="checkbox"
												checked={isActive}
												onChange={() => toggleSegment(segment.id)}
											/>
											<span
												className="arraysubs-box-switch__track"
												style={isActive ? { background: segment.color } : undefined}
											/>
										</label>
										<span className="arraysubs-box-sync__range-label">
											{isActive ? ranges[segment.id] : __("Off", "arraysubs")}
										</span>
										<span
											className="arraysubs-box-sync__seg-label"
											style={{ color: isActive ? segment.color : undefined }}
										>
											{segment.label}
										</span>
									</div>
								);
							})}
						</div>

						<p className="arraysubs-box-section__desc">
							{__(
								"Active segments split the billing cycle between them; disabling a segment lets the remaining ones cover its days. Cycles align to calendar boundaries (months start on the 1st, weeks on the store's start-of-week day, years on January 1) and extra calendar days go to the last active segment.",
								"arraysubs"
							)}
						</p>
					</>
				)}
			</div>
		</div>
	);
};

export default SyncRenewalsBuilder;
