using UnityEngine;

public static class MapDatabase {
    private static MapDefinition[] maps;

    public static MapDefinition[] AllMaps {
        get {
            EnsureMaps();
            return maps;
        }
    }

    public static MapDefinition GetMap(MapId mapId) {
        EnsureMaps();

        for(int i = 0; i < maps.Length; i++)
        {
            if(maps[i].mapId == mapId)
            {
                return CloneMap(maps[i]);
            }
        }

        return CloneMap(maps[0]);
    }

    public static MapDefinition GetMapByIndex(int mapIndex) {
        EnsureMaps();
        int clampedIndex = Mathf.Clamp(mapIndex, 0, maps.Length - 1);
        return CloneMap(maps[clampedIndex]);
    }

    public static int GetIndex(MapId mapId) {
        EnsureMaps();

        for(int i = 0; i < maps.Length; i++)
        {
            if(maps[i].mapId == mapId)
            {
                return i;
            }
        }

        return 0;
    }

    public static int LastMapIndex {
        get {
            EnsureMaps();
            return maps.Length - 1;
        }
    }

    private static void EnsureMaps() {
        if(maps != null && maps.Length > 0)
        {
            return;
        }

        maps = new MapDefinition[] {
            CreateTutorialIncheon(),
            CreateJapan(),
            CreateChina(),
            CreateAmerica()
        };
    }

    private static MapDefinition CreateTutorialIncheon() {
        return new MapDefinition {
            mapId = MapId.TutorialIncheon,
            displayName = "Tutorial / Incheon",
            routeName = "인천공항 출발 준비",
            isTutorial = true,
            targetDistance = 850f,
            timeLimit = 95f,
            clearMileageReward = 150,
            hasNextMap = true,
            nextMapId = MapId.Japan,
            openingSteps = new PlatformSpawner.TutorialStep[] {
                Step(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Jump, -2.4f, 1.05f, "점프", "가방 장애물이 보이면 왼쪽 클릭으로 뛰어넘습니다."),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1f),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.DoubleJump, -2.4f, 2.1f, "2단 점프", "다음 발판이 멀리 있으면 공중에서 한 번 더 왼쪽 클릭합니다."),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1.1f),
                Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, GameManager.TutorialGuideType.Slide, -2.4f, 1.15f, "슬라이드", "천장 표지판이 보이면 오른쪽 클릭을 누르고 지나갑니다."),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1f),
                Step(Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.Damage, -2.4f, 1.15f, "피격", "이번 구간은 일부러 맞아 목숨과 속도 감소를 확인합니다."),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Items, -2.4f, 0.95f, "초밥", "초밥을 먹으면 잃은 목숨을 1 회복합니다.", Platform.ItemPattern.HealthSushi),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Items, -2.4f, 0.9f, "라멘", "라멘을 먹고 다음 충돌을 피해 없이 지나가 봅니다.", Platform.ItemPattern.InvincibleRamen),
                Step(Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.None, -2.4f, 1.05f),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Items, -2.4f, 0.9f, "방어막", "방어막을 먹고 다음 충돌 1회를 막아 봅니다.", Platform.ItemPattern.Shield),
                Step(Platform.PlatformPattern.ForceHit, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.None, -2.4f, 1.05f),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Items, -2.4f, 0.95f, "운동화", "운동화는 속도를 회복해 일정이 늦어지는 것을 줄입니다.", Platform.ItemPattern.SpeedShoes),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.Items, -2.4f, 0.95f, "마일리지 카드", "카드를 먹은 뒤 마일리지를 모으면 획득량이 늘어납니다.", Platform.ItemPattern.MileageCard),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1f),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1f)
            },
            loopSteps = CreateEasyLoop()
        };
    }

    private static MapDefinition CreateJapan() {
        return new MapDefinition {
            mapId = MapId.Japan,
            displayName = "Japan",
            routeName = "후쿠오카 라멘 투어",
            isTutorial = false,
            targetDistance = 1200f,
            timeLimit = 105f,
            clearMileageReward = 250,
            hasNextMap = true,
            nextMapId = MapId.China,
            openingSteps = new PlatformSpawner.TutorialStep[] {
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.2f, 1.8f)
            },
            loopSteps = new PlatformSpawner.TutorialStep[] {
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.2f, 2.05f),
                Step(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.3f, 2.15f),
                Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, GameManager.TutorialGuideType.None, -2.25f, 2.35f),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -1.95f, 2.05f),
                Step(Platform.PlatformPattern.LowLeft, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.35f, 2.1f),
                Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.None, -2.3f, 2.45f)
            }
        };
    }

    private static MapDefinition CreateChina() {
        return new MapDefinition {
            mapId = MapId.China,
            displayName = "China",
            routeName = "베이징 시장길",
            isTutorial = false,
            targetDistance = 1450f,
            timeLimit = 115f,
            clearMileageReward = 350,
            hasNextMap = true,
            nextMapId = MapId.America,
            openingSteps = new PlatformSpawner.TutorialStep[] {
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.1f, 1.9f)
            },
            loopSteps = new PlatformSpawner.TutorialStep[] {
                Step(Platform.PlatformPattern.LowRight, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.25f, 2.0f),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -1.8f, 2.05f),
                Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.LeftPair, GameManager.TutorialGuideType.None, -2.3f, 2.35f),
                Step(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 2.05f),
                Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.RightPair, GameManager.TutorialGuideType.None, -2.25f, 2.35f),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2f, 1.95f)
            }
        };
    }

    private static MapDefinition CreateAmerica() {
        return new MapDefinition {
            mapId = MapId.America,
            displayName = "America",
            routeName = "LA 공항 고속도로",
            isTutorial = false,
            targetDistance = 1700f,
            timeLimit = 125f,
            clearMileageReward = 500,
            hasNextMap = false,
            nextMapId = MapId.America,
            openingSteps = new PlatformSpawner.TutorialStep[] {
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.2f, 1.8f)
            },
            loopSteps = new PlatformSpawner.TutorialStep[] {
                Step(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 1.95f),
                Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.WidePair, GameManager.TutorialGuideType.None, -2.25f, 2.25f),
                Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.None, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -1.8f, 1.9f),
                Step(Platform.PlatformPattern.LowLeft, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.35f, 1.95f),
                Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, GameManager.TutorialGuideType.None, -2.25f, 2.2f),
                Step(Platform.PlatformPattern.LowRight, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.1f, 1.9f)
            }
        };
    }

    private static PlatformSpawner.TutorialStep[] CreateEasyLoop() {
        return new PlatformSpawner.TutorialStep[] {
            Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 2.1f),
            Step(Platform.PlatformPattern.LowMid, Platform.MileagePattern.JumpArc, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.4f, 2.2f),
            Step(Platform.PlatformPattern.Empty, Platform.MileagePattern.SafeLine, SlideObstaclePattern.SlideLayout.Random, GameManager.TutorialGuideType.None, -2.1f, 2.1f),
            Step(Platform.PlatformPattern.Slide, Platform.MileagePattern.SlideLine, SlideObstaclePattern.SlideLayout.CenterPair, GameManager.TutorialGuideType.None, -2.35f, 2.35f)
        };
    }

    private static PlatformSpawner.TutorialStep Step(
        Platform.PlatformPattern platformPattern,
        Platform.MileagePattern mileagePattern,
        SlideObstaclePattern.SlideLayout slideLayout,
        GameManager.TutorialGuideType guideType,
        float yPosition,
        float spawnInterval,
        string title = "",
        string message = "",
        Platform.ItemPattern itemPattern = Platform.ItemPattern.None) {
        return new PlatformSpawner.TutorialStep {
            platformPattern = platformPattern,
            mileagePattern = mileagePattern,
            slideLayout = slideLayout,
            itemPattern = itemPattern,
            guideType = guideType,
            yPosition = yPosition,
            spawnInterval = spawnInterval,
            title = title,
            message = message
        };
    }

    private static MapDefinition CloneMap(MapDefinition source) {
        return new MapDefinition {
            mapId = source.mapId,
            displayName = source.displayName,
            routeName = source.routeName,
            isTutorial = source.isTutorial,
            targetDistance = source.targetDistance,
            timeLimit = source.timeLimit,
            clearMileageReward = source.clearMileageReward,
            hasNextMap = source.hasNextMap,
            nextMapId = source.nextMapId,
            openingSteps = CloneSteps(source.openingSteps),
            loopSteps = CloneSteps(source.loopSteps)
        };
    }

    public static PlatformSpawner.TutorialStep[] CloneSteps(PlatformSpawner.TutorialStep[] source) {
        if(source == null)
        {
            return new PlatformSpawner.TutorialStep[0];
        }

        PlatformSpawner.TutorialStep[] steps = new PlatformSpawner.TutorialStep[source.Length];

        for(int i = 0; i < source.Length; i++)
        {
            PlatformSpawner.TutorialStep sourceStep = source[i];
            steps[i] = Step(
                sourceStep.platformPattern,
                sourceStep.mileagePattern,
                sourceStep.slideLayout,
                sourceStep.guideType,
                sourceStep.yPosition,
                sourceStep.spawnInterval,
                sourceStep.title,
                sourceStep.message,
                sourceStep.itemPattern);
        }

        return steps;
    }
}
