/**
 * Чистая математика теней — без Pixi, тестируется в Vitest.
 * Солнце ходит по дуге в пределах дня из DayNightSpec (dawn..night): тень
 * утром «влево по экрану», вечером «вправо», в полдень короткая; направление
 * проецируется изометрией из плоскости мира — тень всегда лежит на земле.
 * Мир пепельный — свет рассеянный, тени мягкие: альфа скромная, края
 * ступенчатые (рисует makeShadowTexture), геометрия — эллипс, сидящий на базе.
 */

import { type DayNightSpec, DEFAULT_DAY_NIGHT } from './lightSim';
import { DEFAULT_ISO } from '../math/iso';

/** Цвет тени — нейтральный тёмно-серый (пепельная гамма, не чёрный). */
export const SHADOW_COLOR = 0x2f2f38;

/** Гладкая ступень 0..1 (нулевой наклон на краях — без рывков альфы). */
function smooth(t: number): number {
    const x = Math.max(0, Math.min(1, t));
    return x * x * (3 - 2 * x);
}

/** Состояние солнца для теней: направление тени (экран), длина, альфа. */
export interface SunShadow {
    /** Единичный вектор тени на экране (dx вправо, dy вниз); лежит на изо-земле. */
    dirX: number;
    dirY: number;
    /** Длина тени на единицу высоты объекта (короткая в полдень). */
    len: number;
    /** Сила тени 0..1 (пепельный мир — солнце рассеянное). */
    alpha: number;
}

/**
 * Солнце по часам суток: null — ночи (тьма рисует darkness-слой, тени от
 * солнца не видны). Границы и разгон альфы — из DayNightSpec: подъём
 * dawn..day, спад dusk..night. Направление тени считается АЗИМУТОМ в
 * плоскости мира и проецируется изометрией (мировой юг → экран влево-вниз,
 * мировая диагональ юго-восток → ровно вниз): любой вектор с этой дуги
 * лежит на земле — тень не «стекает по стене» и не отрывает объект от пола.
 */
export function sunShadow(hours: number, spec: DayNightSpec = DEFAULT_DAY_NIGHT): SunShadow | null {
    const t = ((hours % 24) + 24) % 24;
    const rise = spec.dawn;
    const set = spec.night;
    if (t < rise || t >= set) return null;
    const up = smooth((t - rise) / Math.max(0.001, spec.day - rise));
    const down = 1 - smooth((t - spec.dusk) / Math.max(0.001, set - spec.dusk));
    const k = (t - rise) / (set - rise); // 0..1 — путь солнца за день
    const az = (Math.PI / 2) * (1 - k); // мировой юг (утро) → юго-восток (вечер)
    const gx = Math.cos(az);
    const gy = Math.sin(az);
    const px = (gx - gy) * (DEFAULT_ISO.tileW / 2);
    const py = (gx + gy) * (DEFAULT_ISO.tileH / 2);
    const n = Math.hypot(px, py);
    const len = 0.55 + 1.05 * Math.pow(Math.abs(k - 0.5) * 2, 1.4);
    return { dirX: px / n, dirY: py / n, len, alpha: 0.5 * Math.min(up, down) };
}

/** Размещение блоба-тени относительно базы объекта (в px виртуального экрана). */
export interface BlobPlacement {
    /** Центр эллипса относительно точки базы (ноги/основания). */
    x: number;
    y: number;
    /** Поворот эллипса — вдоль направления тени. */
    rotation: number;
    /** Полуоси эллипса, px. */
    scaleX: number;
    scaleY: number;
    /** Прозрачность — сила солнца. */
    alpha: number;
}

/**
 * Эллипс тени для объекта высотой heightPx с «толщиной» radiusPx. Масса
 * эллипса сидит у базы: центр лишь чуть съезжает вдоль тени, а ближний край
 * заходит за базу — иначе видимая тёмная масса висит в стороне от объекта
 * и тот читается «летающим». Вылет вдоль направления растёт с высотой и
 * низким солнцем (len), ширина поперёк почти не меняется от длины.
 */
export function blobPlacement(radiusPx: number, heightPx: number, sun: SunShadow): BlobPlacement {
    const reach = heightPx * sun.len;
    const center = radiusPx * 0.3 + reach * 0.2; // центр массы от базы
    const a = center + radiusPx * 0.55 + reach * 0.22; // полуось вдоль тени
    const b = radiusPx * (0.75 + 0.25 * Math.min(1, sun.len)); // полуось поперёк
    return {
        x: sun.dirX * center,
        y: sun.dirY * center,
        rotation: Math.atan2(sun.dirY, sun.dirX),
        scaleX: a,
        scaleY: b,
        alpha: sun.alpha
    };
}