import { Direction } from '../core/Define';
import { LevelConfig, LevelEntityTextures, SpawnConfig, SpawnKind } from '../level/LevelTypes';
import { resolvePropPlacement } from '../level/EntitySpawnPlacement';
import type { PropPlacement } from '../level/EntitySpawnPlacement';
import { getThemeBackground, getThemeEntities, getThemeTextureFolder, isThemeDatabaseReady } from '../theme/ThemeRegistry';
import {
    entityTextureCandidates,
    vehicleSpriteRoleForDirection,
    vehicleThemeFieldForDirection,
    allVehicleDirectionTextureCandidates,
    type EntitySpriteRole,
} from './ThemeEntityTextures';

const THEME_TEXTURE_FOLDER: Record<string, string> = {
    default: 'default',
    silu: 'silu',
    SILU: 'silu',
    chinese: 'chinese',
    redArmy: 'redArmy',
    redarmy: 'redArmy',
    numMan: 'numMan',
    snow: 'snow',
    sanxing: 'sanxing',
};

function resolveThemeFolder(theme: string | undefined): string {
    if (!theme) return 'silu';
    const trimmed = String(theme).trim();
    if (isThemeDatabaseReady()) return getThemeTextureFolder(trimmed);
    return THEME_TEXTURE_FOLDER[trimmed] ?? THEME_TEXTURE_FOLDER[trimmed.toLowerCase()] ?? trimmed;
}

export interface EntityVisualOptions {
    theme?: string;
    entityTextures?: LevelEntityTextures;
    /** 单个 spawn 的贴图覆盖（可拾取物常用） */
    spawnTexture?: string;
    /** 可拾取物放置高度（Unity Prop / nProp） */
    propPlacement?: PropPlacement;
}

/** 统一为 resources 相对路径，无 .png 后缀 */
export function normalizeTexturePath(raw: string | undefined): string | undefined {
    if (!raw) return undefined;
    let p = String(raw).trim().replace(/\\/g, '/');
    if (!p) return undefined;
    if (p.startsWith('assets/resources/')) p = p.slice('assets/resources/'.length);
    if (p.startsWith('resources/')) p = p.slice('resources/'.length);
    if (p.startsWith('/')) p = p.slice(1);
    if (p.endsWith('.png')) p = p.slice(0, -4);
    return p;
}

function themePropCandidates(theme: string | undefined): string[] {
    const folder = resolveThemeFolder(theme);
    return [
        `textures/${folder}/Prop_kuai1`,
        'textures/silu/Prop_kuai1',
    ];
}

function themeGroundPropCandidates(theme: string | undefined): string[] {
    const folder = resolveThemeFolder(theme);
    return [
        `textures/${folder}/nProp_kuai1`,
        'textures/silu/nProp_kuai1',
    ];
}

/** Prop_kuai2 → nProp_kuai2；Prop → nProp */
export function toGroundPropTexturePath(blockPath: string | undefined): string | undefined {
    const norm = normalizeTexturePath(blockPath);
    if (!norm) return undefined;
    const slash = norm.lastIndexOf('/');
    const dir = slash >= 0 ? norm.slice(0, slash + 1) : '';
    const file = slash >= 0 ? norm.slice(slash + 1) : norm;
    if (file.startsWith('Prop_')) return `${dir}n${file}`;
    if (file === 'Prop') return `${dir}nProp`;
    if (file.startsWith('nProp')) return norm;
    return norm.replace(/\/Prop([^/]*)$/, '/nProp$1');
}

function themeDbEntityPath(
    theme: string | undefined,
    field: keyof NonNullable<ReturnType<typeof getThemeEntities>>,
): string | undefined {
    const ent = getThemeEntities(theme);
    if (!ent) return undefined;
    return normalizeTexturePath(ent[field]);
}

function themeDbEntityCandidates(
    theme: string | undefined,
    field: keyof NonNullable<ReturnType<typeof getThemeEntities>>,
    role: EntitySpriteRole,
): string[] {
    const db = themeDbEntityPath(theme, field);
    const legacy = entityTextureCandidates(theme, role);
    return withFallback(db, legacy);
}

function levelVehicleTextureOverride(
    direction: Direction,
    entityTextures: LevelEntityTextures | undefined,
): string | undefined {
    if (!entityTextures) return undefined;
    const field = vehicleThemeFieldForDirection(direction);
    const direct = normalizeTexturePath(entityTextures[field]);
    if (direct) return direct;
    const front = isEntityFront(direction);
    return normalizeTexturePath(
        front ? entityTextures.vehicleFront : entityTextures.vehicleBack,
    );
}

function withFallback(primary: string | undefined, fallbacks: string[]): string[] {
    const out: string[] = [];
    const norm = normalizeTexturePath(primary);
    if (norm) out.push(norm);
    for (const p of fallbacks) {
        if (!out.includes(p)) out.push(p);
    }
    return out;
}

function themePropCandidatesWithDb(theme: string | undefined): string[] {
    const db = themeDbEntityPath(theme, 'prop');
    if (db) return [db];
    return themePropCandidates(theme);
}

function themeGroundPropCandidatesWithDb(
    theme: string | undefined,
    blockPropPath?: string,
): string[] {
    const dbGround = themeDbEntityPath(theme, 'propGround');
    if (dbGround) return [dbGround];
    const derived = toGroundPropTexturePath(blockPropPath ?? themeDbEntityPath(theme, 'prop'));
    if (derived) return [derived];
    return themeGroundPropCandidates(theme);
}

export function isEntityFront(direction: Direction | undefined): boolean {
    return direction === Direction.South || direction === Direction.East;
}

export function entityFlipX(direction: Direction | undefined): boolean {
    return direction === Direction.West || direction === Direction.East;
}

/** @deprecated 载具已改用四向贴图；玩家仍用 IsFront + flipX */
export function resolveVehicleOrientation(direction: Direction | undefined): {
    front: boolean;
    flipX: boolean;
} {
    const dir = direction ?? Direction.North;
    return {
        front: isEntityFront(dir),
        flipX: entityFlipX(dir),
    };
}

export function resolvePlayerTexturePaths(
    direction: Direction | undefined,
    options: EntityVisualOptions = {},
): string[] {
    const front = isEntityFront(direction);
    const custom = front
        ? normalizeTexturePath(options.entityTextures?.playerFront)
        : normalizeTexturePath(options.entityTextures?.playerBack);
    const spawnCustom = normalizeTexturePath(options.spawnTexture);
    const themePaths = themeDbEntityCandidates(
        options.theme,
        front ? 'playerFront' : 'playerBack',
        front ? 'playerFront' : 'playerBack',
    );
    if (spawnCustom) return withFallback(spawnCustom, themePaths);
    if (custom) return withFallback(custom, themePaths);
    return themePaths;
}

/** 载具四向贴图路径（北/东/南/西各一张，转向时直接切换，无 flipX） */
export function resolveVehicleTexturePaths(
    direction: Direction | undefined,
    options: EntityVisualOptions = {},
): string[] {
    const dir = direction ?? Direction.North;
    const field = vehicleThemeFieldForDirection(dir);
    const role = vehicleSpriteRoleForDirection(dir);
    const custom = levelVehicleTextureOverride(dir, options.entityTextures);
    const spawnCustom = normalizeTexturePath(options.spawnTexture);
    const themePaths = themeDbEntityCandidates(options.theme, field, role);
    if (spawnCustom) return withFallback(spawnCustom, themePaths);
    if (custom) return withFallback(custom, themePaths);
    return themePaths;
}

/** 预加载主题载具四向贴图 */
export function collectThemeVehicleTexturePaths(
    theme: string | undefined,
    entityTextures?: LevelEntityTextures,
): string[] {
    const set = new Set<string>();
    const add = (p: string | undefined) => {
        const n = normalizeTexturePath(p);
        if (n) set.add(n);
    };
    for (const p of allVehicleDirectionTextureCandidates(theme)) add(p);
    if (entityTextures) {
        for (let d = Direction.North; d <= Direction.West; d++) {
            add(levelVehicleTextureOverride(d, entityTextures));
        }
    }
    return Array.from(set);
}

export function resolvePropTexturePaths(options: EntityVisualOptions = {}): string[] {
    const spawnCustom = normalizeTexturePath(options.spawnTexture);
    const levelBlock = normalizeTexturePath(options.entityTextures?.prop);
    const levelGround = normalizeTexturePath(options.entityTextures?.propGround);
    const onGround = options.propPlacement === 'ground';
    if (spawnCustom) {
        const custom = onGround ? toGroundPropTexturePath(spawnCustom) ?? spawnCustom : spawnCustom;
        const fallback = onGround
            ? themeGroundPropCandidatesWithDb(options.theme, levelBlock)
            : themePropCandidatesWithDb(options.theme);
        return withFallback(custom, fallback);
    }
    if (onGround && levelGround) {
        return withFallback(levelGround, themeGroundPropCandidatesWithDb(options.theme, levelBlock));
    }
    if (levelBlock) {
        const custom = onGround ? toGroundPropTexturePath(levelBlock) ?? levelBlock : levelBlock;
        return withFallback(custom, onGround
            ? themeGroundPropCandidatesWithDb(options.theme, levelBlock)
            : themePropCandidatesWithDb(options.theme));
    }
    return onGround
        ? themeGroundPropCandidatesWithDb(options.theme)
        : themePropCandidatesWithDb(options.theme);
}

export function resolveEntityTexturePaths(
    kind: SpawnKind,
    direction: Direction | undefined,
    options: EntityVisualOptions = {},
): string[] {
    if (kind === 'player') return resolvePlayerTexturePaths(direction, options);
    if (kind === 'vehicle') return resolveVehicleTexturePaths(direction, options);
    if (kind === 'prop' || kind === 'prop_decor') return resolvePropTexturePaths(options);
    return themePropCandidates(options.theme);
}

/** 预加载关卡用到的实体贴图（仅主路径，不扫全量 fallback） */
export function collectLevelEntityTexturePaths(
    theme: string | undefined,
    entityTextures?: LevelEntityTextures,
    spawns?: SpawnConfig[],
    levelConfig?: Pick<LevelConfig, 'ground' | 'border'>,
): string[] {
    const set = new Set<string>();
    const add = (p: string | undefined) => {
        const n = normalizeTexturePath(p);
        if (n) set.add(n);
    };
    const addPrimary = (paths: string[]) => {
        for (const p of paths) add(p);
    };

    add(getThemeBackground(theme));

    const visualBase: EntityVisualOptions = { theme, entityTextures };
    const list = spawns ?? [];

    for (const s of list) {
        if (s.kind === 'player') {
            addPrimary(resolvePlayerTexturePaths(
                parseSpawnDirection(s.playerDirection) ?? Direction.South,
                { ...visualBase, spawnTexture: s.texture },
            ));
        } else if (s.kind === 'vehicle') {
            for (let d = Direction.North; d <= Direction.West; d++) {
                addPrimary(resolveVehicleTexturePaths(d, { ...visualBase, spawnTexture: s.texture }));
            }
        } else if (s.kind === 'prop') {
            const placement: PropPlacement = levelConfig
                ? resolvePropPlacement(s, levelConfig as LevelConfig)
                : (s.propPlacement ?? 'block');
            addPrimary(resolvePropTexturePaths({
                ...visualBase,
                spawnTexture: s.texture,
                propPlacement: placement,
            }));
        } else if (s.kind === 'prop_decor') {
            addPrimary(resolvePropTexturePaths(visualBase));
        }
    }

    if (!list.length) {
        addPrimary(resolvePlayerTexturePaths(Direction.South, visualBase));
        for (const p of collectThemeVehicleTexturePaths(theme, entityTextures)) add(p);
        addPrimary(resolvePropTexturePaths(visualBase));
    }

    return Array.from(set);
}

function parseSpawnDirection(raw: unknown): Direction | undefined {
    if (typeof raw === 'number') return raw as Direction;
    if (typeof raw !== 'string') return undefined;
    const name = raw.replace(/^Direction\./, '');
    const key = name as keyof typeof Direction;
    if (Object.prototype.hasOwnProperty.call(Direction, key)) {
        const v = Direction[key];
        if (typeof v === 'number') return v as Direction;
    }
    return undefined;
}
