import { JsonAsset, resources } from 'cc';
import { CELL_PIXEL } from '../core/GridConstants';
import type {
    ThemeConfig,
    ThemeDatabaseFile,
    ThemeEntityConfig,
    ThemeTileConfig,
    ThemeHudConfig,
    ThemeHudIconKey,
    EntityDisplayGlobalConfig,
    EntityDisplayCellBox,
    EntityDisplayKind,
    EntityDisplayScaleConfig,
} from './ThemeTypes';

const DB_PATH = 'theme/themes-database';

/** scale=1 时的包围盒（相对 100px 格子），宽高比固定 */
export const ENTITY_DISPLAY_BASE: Record<EntityDisplayKind, EntityDisplayCellBox> = {
    player: { w: 0.68, h: 0.9 },
    vehicle: { w: 0.96, h: 0.88 },
    /** 与 Unity Prop_kuai* 竖长比例一致（约 49×69） */
    prop: { w: 0.52, h: 0.69 },
    propGround: { w: 0.52, h: 0.69 },
};

const HALF_H = CELL_PIXEL * 0.25;

/** Unity Prop_sanxing checkPoint collider ≈ +0.144 world (PPU 100) */
export const DEFAULT_PROP_BLOCK_Y_OFFSET = 14;
/** Unity nProp_sanxing checkPoint collider ≈ -0.115 world */
export const DEFAULT_PROP_GROUND_Y_OFFSET = -11;
/** 空地/载具格角色与载具：补齐无 Baseblock 时的视觉高度（约半格） */
export const DEFAULT_MOVER_EMPTY_CELL_Y_OFFSET = HALF_H;
/** JumpBlock 自动补偿之上的主题微调（px） */
export const DEFAULT_MOVER_JUMP_CELL_Y_OFFSET = 0;
/** 骑乘时角色相对载具节点抬高，对齐载具甲板（约 vehicle 包围盒 40%） */
export const DEFAULT_PLAYER_RIDE_Y_OFFSET = HALF_H * 0.88;
export const DEFAULT_PLAYER_STAND_Y_OFFSET = 0;

export const DEFAULT_ENTITY_DISPLAY: EntityDisplayGlobalConfig = {
    player: { scale: 1 },
    vehicle: { scale: 1 },
    prop: { scale: 1 },
    propGround: { scale: 1 },
    propBlockYOffset: DEFAULT_PROP_BLOCK_Y_OFFSET,
    propGroundYOffset: DEFAULT_PROP_GROUND_Y_OFFSET,
    moverEmptyCellYOffset: DEFAULT_MOVER_EMPTY_CELL_Y_OFFSET,
    moverJumpCellYOffset: DEFAULT_MOVER_JUMP_CELL_Y_OFFSET,
    playerRideYOffset: DEFAULT_PLAYER_RIDE_Y_OFFSET,
    playerStandYOffset: DEFAULT_PLAYER_STAND_Y_OFFSET,
};

const DISPLAY_KINDS: EntityDisplayKind[] = ['player', 'vehicle', 'prop', 'propGround'];

const HUD_ICON_KEYS: ThemeHudIconKey[] = [
    'navigation', 'revert', 'speed1', 'speed2', 'speed4',
    'zoomIn', 'zoomOut', 'audioOn', 'audioOff',
];

/** Unity 导入的内置 HUD 回退（themes-database 未配置 hud 时使用） */
const FALLBACK_HUD: Record<string, ThemeHudConfig> = {
    silu: {
        navigation: 'textures/silu/anniu_03',
        revert: 'textures/silu/anniu_06',
        speed1: 'textures/silu/anniu_08',
        speed2: 'textures/silu/anniu_10',
        speed4: 'textures/silu/anniu_12',
        zoomIn: 'textures/silu/anniu_17',
        zoomOut: 'textures/silu/anniu_19',
        audioOn: 'textures/silu/anniu_22',
        audioOff: 'textures/silu/anniu_21',
    },
};

const THEME_ID_ALIASES: Record<string, string> = {
    default: 'silu',
    SILU: 'silu',
    redArmy: 'redarmy',
};

const FOLDER_TO_THEME_ID: Record<string, string> = {
    redArmy: 'redarmy',
};

function asTrimmedString(v: unknown): string | undefined {
    if (v == null) return undefined;
    if (typeof v === 'string') {
        const s = v.trim();
        return s || undefined;
    }
    if (typeof v === 'number' || typeof v === 'boolean') {
        return String(v);
    }
    return undefined;
}

export function resolveThemeId(themeId: string | undefined): string {
    const trimmed = asTrimmedString(themeId);
    if (!trimmed) return 'silu';
    const raw = trimmed;
    if (themesMap[raw]) return raw;
    const alias = THEME_ID_ALIASES[raw];
    if (alias && themesMap[alias]) return alias;
    const fromFolder = FOLDER_TO_THEME_ID[raw];
    if (fromFolder && themesMap[fromFolder]) return fromFolder;
    const lower = raw.toLowerCase();
    if (themesMap[lower]) return lower;
    return raw;
}

function mergeHudConfig(raw: ThemeHudConfig | undefined, themeId: string): ThemeHudConfig {
    const layers: ThemeHudConfig[] = [FALLBACK_HUD.silu];
    if (FALLBACK_HUD[themeId]) layers.push(FALLBACK_HUD[themeId]!);
    if (raw) layers.push(raw);
    return Object.assign({}, ...layers);
}

export function getThemeHudConfig(themeId: string | undefined): ThemeHudConfig {
    const id = resolveThemeId(themeId);
    const cfg = getThemeConfig(id);
    return mergeHudConfig(cfg?.hud, themesMap[id] ? id : 'silu');
}

export function getThemeHudIconPath(themeId: string | undefined, icon: ThemeHudIconKey): string | undefined {
    const hud = getThemeHudConfig(themeId);
    const path = asTrimmedString(hud[icon]);
    if (path) return path;
    return FALLBACK_HUD.silu[icon];
}

export function getThemeHudIconScale(themeId: string | undefined): { x: number; y: number } {
    const hud = getThemeHudConfig(themeId);
    return {
        x: hud.iconScaleX ?? 1,
        y: hud.iconScaleY ?? 1,
    };
}

/** 左上角肖像贴图（优先 entities.portrait） */
export function getThemePortraitPath(themeId: string | undefined): string | undefined {
    const id = resolveThemeId(themeId);
    const ent = getThemeConfig(id)?.entities;
    const portrait = asTrimmedString(ent?.portrait);
    if (portrait) return portrait;
    return asTrimmedString(ent?.playerFront);
}

/** 左上角肖像水平翻转（默认朝右） */
export function getThemePortraitFlipX(themeId: string | undefined): boolean {
    const hud = getThemeHudConfig(themeId);
    return hud.portraitFlipX ?? true;
}

const DEFAULT_PORTRAIT_SCALE = 1.35;

export function getThemePortraitScale(themeId: string | undefined): number {
    const hud = getThemeHudConfig(themeId);
    const raw = hud.portraitScale;
    if (raw != null && Number.isFinite(raw)) {
        return Math.max(0.5, Math.min(2.5, raw));
    }
    return DEFAULT_PORTRAIT_SCALE;
}

export function getThemeHudIconCandidates(themeId: string | undefined, icon: ThemeHudIconKey): string[] {
    const primary = getThemeHudIconPath(themeId, icon);
    if (!primary) return [];
    // 不回退到 silu 碎图，避免非丝路主题下倍速/音量变成黄圆按钮
    return [primary];
}

function clampScale(v: number, fallback = 1): number {
    if (!Number.isFinite(v)) return fallback;
    return Math.max(0.1, Math.min(2, v));
}

function readScale(raw: EntityDisplayScaleConfig | EntityDisplayCellBox | undefined, base: EntityDisplayCellBox): number {
    if (raw && 'scale' in raw && raw.scale != null) {
        return clampScale(raw.scale);
    }
    const legacy = raw as EntityDisplayCellBox | undefined;
    if (legacy?.w != null && legacy?.h != null) {
        return clampScale(Math.min(legacy.w / base.w, legacy.h / base.h));
    }
    if (legacy?.w != null) return clampScale(legacy.w / base.w);
    if (legacy?.h != null) return clampScale(legacy.h / base.h);
    return 1;
}

function mergeScale(raw: EntityDisplayScaleConfig | EntityDisplayCellBox | undefined, kind: EntityDisplayKind): EntityDisplayScaleConfig {
    return { scale: readScale(raw, ENTITY_DISPLAY_BASE[kind]) };
}

function readYOffset(raw: number | undefined, fallback: number): number {
    if (raw == null || !Number.isFinite(raw)) return fallback;
    return raw;
}

/** 读取 JSON 中的等比缩放配置（兼容旧版 w/h） */
export function mergeEntityDisplay(
    raw: (Partial<Record<EntityDisplayKind, EntityDisplayScaleConfig | EntityDisplayCellBox>> & Pick<EntityDisplayGlobalConfig, 'propBlockYOffset' | 'propGroundYOffset' | 'moverEmptyCellYOffset' | 'playerRideYOffset' | 'playerStandYOffset'>) | undefined,
): EntityDisplayGlobalConfig {
    const prop = mergeScale(raw?.prop, 'prop');
    const blockY = readYOffset(raw?.propBlockYOffset, DEFAULT_PROP_BLOCK_Y_OFFSET);
    return {
        player: mergeScale(raw?.player, 'player'),
        vehicle: mergeScale(raw?.vehicle, 'vehicle'),
        prop,
        propGround: mergeScale(raw?.propGround ?? raw?.prop, 'propGround'),
        propBlockYOffset: blockY,
        propGroundYOffset: readYOffset(raw?.propGroundYOffset, DEFAULT_PROP_GROUND_Y_OFFSET),
        moverEmptyCellYOffset: readYOffset(raw?.moverEmptyCellYOffset, DEFAULT_MOVER_EMPTY_CELL_Y_OFFSET),
        moverJumpCellYOffset: readYOffset(raw?.moverJumpCellYOffset, DEFAULT_MOVER_JUMP_CELL_Y_OFFSET),
        playerRideYOffset: readYOffset(raw?.playerRideYOffset, DEFAULT_PLAYER_RIDE_Y_OFFSET),
        playerStandYOffset: readYOffset(raw?.playerStandYOffset, DEFAULT_PLAYER_STAND_Y_OFFSET),
    };
}

/** 骑乘载具时角色视觉 Y 抬高（逻辑格点仍与载具一致） */
export function getThemePlayerRideYOffset(themeId: string | undefined): number {
    const cfg = getThemeEntityDisplayScales(themeId);
    return cfg.playerRideYOffset ?? DEFAULT_PLAYER_RIDE_Y_OFFSET;
}

/** 角色站立 Y 偏移（负值降低） */
export function getThemePlayerStandYOffset(themeId: string | undefined): number {
    const cfg = getThemeEntityDisplayScales(themeId);
    return cfg.playerStandYOffset ?? DEFAULT_PLAYER_STAND_Y_OFFSET;
}

/** 空地/载具格角色与载具 Y 补偿（有砖块格为 0） */
export function getThemeMoverEmptyCellYOffset(themeId: string | undefined): number {
    const cfg = getThemeEntityDisplayScales(themeId);
    return cfg.moverEmptyCellYOffset ?? cfg.propBlockYOffset ?? DEFAULT_MOVER_EMPTY_CELL_Y_OFFSET;
}

/** JumpBlock 额外 Y 抬高（在自动 pivot 差值之上） */
export function getThemeMoverJumpCellYOffset(themeId: string | undefined): number {
    const cfg = getThemeEntityDisplayScales(themeId);
    return cfg.moverJumpCellYOffset ?? DEFAULT_MOVER_JUMP_CELL_Y_OFFSET;
}

/** 可拾取物砖块/空地 Y 偏移（来自主题 entityDisplay，缺省为 Unity Prop/nProp 换算值） */
export function getThemePropPlacementOffsets(themeId: string | undefined): { block: number; ground: number } {
    const cfg = getThemeEntityDisplayScales(themeId);
    return {
        block: cfg.propBlockYOffset ?? DEFAULT_PROP_BLOCK_Y_OFFSET,
        ground: cfg.propGroundYOffset ?? DEFAULT_PROP_GROUND_Y_OFFSET,
    };
}

/** 由缩放算出运行时包围盒（保持默认宽高比） */
export function entityDisplayCellBoxes(scales: EntityDisplayGlobalConfig): Record<EntityDisplayKind, EntityDisplayCellBox> {
    const out = {} as Record<EntityDisplayKind, EntityDisplayCellBox>;
    for (const kind of DISPLAY_KINDS) {
        const s = scales[kind].scale;
        const base = ENTITY_DISPLAY_BASE[kind];
        out[kind] = { w: base.w * s, h: base.h * s };
    }
    return out;
}

export function getGlobalEntityDisplay(): Record<EntityDisplayKind, EntityDisplayCellBox> {
    return entityDisplayCellBoxes(getGlobalEntityDisplayScales());
}

/** @deprecated 使用 getThemeEntityDisplayScales(themeId) */
export function getGlobalEntityDisplayScales(): EntityDisplayGlobalConfig {
    return mergeEntityDisplay(fileCache?.entityDisplay);
}

export function getThemeEntityDisplayScales(themeId: string | undefined): EntityDisplayGlobalConfig {
    const cfg = getThemeConfig(resolveThemeId(themeId));
    if (cfg?.entityDisplay) {
        return mergeEntityDisplay(cfg.entityDisplay);
    }
    if (fileCache?.entityDisplay) {
        return mergeEntityDisplay(fileCache.entityDisplay);
    }
    return mergeEntityDisplay(undefined);
}

export function getThemeEntityDisplayCellBoxes(themeId: string | undefined): Record<EntityDisplayKind, EntityDisplayCellBox> {
    return entityDisplayCellBoxes(getThemeEntityDisplayScales(themeId));
}

let fileCache: ThemeDatabaseFile | null = null;
let themesMap: Record<string, ThemeConfig> = {};
let sortedIds: string[] = [];
let loadPromise: Promise<void> | null = null;

function rebuildIndex() {
    sortedIds = Object.keys(themesMap).sort((a, b) => a.localeCompare(b));
}

function ingestFile(data: ThemeDatabaseFile) {
    migrateLegacyEntityDisplay(data);
    fileCache = data;
    themesMap = { ...(data.themes ?? {}) };
    rebuildIndex();
}

/** 将旧版根级 entityDisplay 迁移到各主题（仅补缺失项） */
function migrateLegacyEntityDisplay(data: ThemeDatabaseFile) {
    const legacy = data.entityDisplay;
    if (!legacy || !data.themes) return;
    for (const id of Object.keys(data.themes)) {
        if (!data.themes[id].entityDisplay) {
            data.themes[id].entityDisplay = mergeEntityDisplay(legacy);
        }
    }
}

export function loadThemeDatabase(): Promise<void> {
    if (loadPromise) return loadPromise;
    loadPromise = new Promise((resolve, reject) => {
        resources.load(DB_PATH, JsonAsset, (err, asset) => {
            if (err || !asset?.json) {
                console.warn('[ThemeDatabase] 未找到 themes-database.json，将使用内置回退', err);
                ingestFile({ version: 1, themes: {} });
                resolve();
                return;
            }
            ingestFile(asset.json as ThemeDatabaseFile);
            console.log(`[ThemeDatabase] 已加载 ${sortedIds.length} 个主题: ${sortedIds.join(', ')}`);
            resolve();
        });
    });
    return loadPromise;
}

/** 重新读取 themes-database.json（主题控制器保存全局尺寸后生效） */
export function reloadThemeDatabase(): Promise<void> {
    fileCache = null;
    loadPromise = null;
    themesMap = {};
    sortedIds = [];
    return new Promise((resolve) => {
        resources.release(DB_PATH);
        loadThemeDatabase().then(resolve);
    });
}

export function isThemeDatabaseReady(): boolean {
    return fileCache !== null;
}

export function getThemeIds(): string[] {
    return [...sortedIds];
}

export function getThemeConfig(themeId: string | undefined): ThemeConfig | null {
    if (!themeId) return null;
    return themesMap[themeId] ?? null;
}

export function hasTheme(themeId: string): boolean {
    return themeId in themesMap;
}

export function getThemeTextureFolder(themeId: string | undefined): string {
    const cfg = getThemeConfig(themeId);
    if (cfg?.textureFolder) return cfg.textureFolder;
    if (themeId === 'redarmy') return 'redArmy';
    return themeId ?? 'silu';
}

export function getThemeEntities(themeId: string | undefined): ThemeEntityConfig | null {
    const cfg = getThemeConfig(themeId);
    return cfg?.entities ?? null;
}

export function getThemeBackground(themeId: string | undefined): string | undefined {
    const cfg = getThemeConfig(themeId);
    return asTrimmedString(cfg?.background);
}

export function getThemeTiles(themeId: string | undefined): ThemeTileConfig | null {
    const cfg = getThemeConfig(themeId);
    return cfg?.tiles ?? null;
}

export function getThemeBorderDecorKey(themeId: string | undefined): string | undefined {
    const cfg = getThemeConfig(resolveThemeId(themeId));
    return asTrimmedString(cfg?.borderDecorKey);
}

/** 关卡 JSON / Unity 预制体里常见的装饰砖 tileKey，统一映射到 themes-database 的 borderDecor */
const BORDER_DECOR_ALIASES = new Set([
    'kuai11',
    'Decor23',
    'borderDecor',
    '素材切图-23',
    '素材切图2-23',
    '小游戏素材红色_03',
]);

/** 按 tileKey 解析贴图路径（含 borderDecorKey 与跨主题别名） */
export function getThemeTilePath(themeId: string | undefined, tileKey: unknown): string | undefined {
    const id = resolveThemeId(themeId);
    const tiles = getThemeTiles(id);
    if (!tiles) return undefined;
    const key = asTrimmedString(tileKey);
    if (!key) return undefined;
    if (key === 'Baseblock' && tiles.Baseblock) return tiles.Baseblock;
    if (key === 'JumpBlock' && tiles.JumpBlock) return tiles.JumpBlock;
    if (key === 'WallBlock' && tiles.WallBlock) return tiles.WallBlock;
    const decorKey = getThemeBorderDecorKey(id);
    if (tiles.borderDecor) {
        if (key === decorKey || BORDER_DECOR_ALIASES.has(key)) {
            return tiles.borderDecor;
        }
    }
    if (tiles.borderDecor && key === 'borderDecor') return tiles.borderDecor;
    return undefined;
}

export function setTheme(themeId: string, config: ThemeConfig): void {
    themesMap[themeId] = { ...config };
    if (fileCache) fileCache.themes[themeId] = themesMap[themeId];
    rebuildIndex();
}

export function removeTheme(themeId: string): boolean {
    if (!(themeId in themesMap)) return false;
    delete themesMap[themeId];
    if (fileCache?.themes) delete fileCache.themes[themeId];
    rebuildIndex();
    return true;
}

export function exportDatabaseJson(): string {
    const payload: ThemeDatabaseFile = fileCache ?? { version: 1, themes: {} };
    payload.updatedAt = new Date().toISOString();
    payload.themes = { ...themesMap };
    return JSON.stringify(payload, null, 2);
}
