package main

import (
	"math/rand"
	"time"

	"github.com/ryomak/p5go"
)

const (
	CANVAS_WIDTH        = 400
	CANVAS_HEIGHT       = 400
	BASE_Y              = CANVAS_HEIGHT * 1
	BUILDING_BASE_WIDTH = 80
	STAR_COUNT          = 50
	SPRITE_SCALE        = 5 // 建物スプライトは16×16で拡大
	TREE_SCALE          = 3 // 木は8×8ドットを小さめに表示
	MOON_SCALE          = 4 // 月は8×8ドット、適度な大きさに表示
	TREE_COUNT          = 4
)

// パレット(0=透明)
// 1: 壁色(建物と共通)
// 2: 窓色
// 3: 屋根色
// 6: 月用の色
var palette = map[int][3]int{
	1: {70, 70, 90},              // 壁
	2: {255, 220, 100},           // 窓
	3: generateRandomRoofColor(), // 屋根
	6: {250, 250, 200},           // 月
}

// 屋根色のランダム生成関数
func generateRandomRoofColor() [3]int {
	rand.Seed(time.Now().UnixNano())

	// 値をランダムに生成
	r := rand.Intn(141) + 50 // 50~190の範囲
	g := rand.Intn(141) + 50
	b := rand.Intn(141) + 50

	// 条件を満たすまで再生成
	for !isValidColor(r, g, b) {
		r = rand.Intn(141) + 50
		g = rand.Intn(141) + 50
		b = rand.Intn(141) + 50
	}

	return [3]int{r, g, b}
}

// 条件チェック関数
func isValidColor(r, g, b int) bool {
	// 120以上の値の個数をカウント
	countAbove120 := 0
	if r >= 120 {
		countAbove120++
	}
	if g >= 120 {
		countAbove120++
	}
	if b >= 120 {
		countAbove120++
	}

	// 条件: 1つまたは2つは120以上、3つとも120以上は不可
	return countAbove120 >= 1 && countAbove120 <= 2
}

// ─────────────────────────────
// 【建物スプライト】(16×16ドット)

// 高層ビル(屋根は1行のみのフラットな屋根)
var highBuildingSprite1 = [][]int{
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0}, // 屋根行
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
}

// 商業ビル(屋根は1行のみ)
var commercialBuildingSprite = [][]int{
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0}, // 屋根行
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
	{1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
	{1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
	{1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
	{1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
	{1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 1, 2, 2, 2, 1, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
}

// 三角屋根の建物(屋根は三角形)
var triangleBuildingSprite = [][]int{
	{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 0, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0},
	{0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0},
	{0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0},
	{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
	{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0, 0, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
	{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0, 0, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
	{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0, 0, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
	{1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0, 0, 0},
	{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
}

// タワー(屋根なし・シンプルな縦長パターン)
var towerSprite = [][]int{
	{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
	{0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 0, 0, 0},
}

// ─────────────────────────────
// 【小さい家スプライト】(新規:8×?ドット)
// 手前レイヤー用:大きすぎる建物は排除し、小さい家のみ表示する
// 上部(屋根)はキー3、下部(壁・窓)はキー1,2 を使用
var smallHouseSprite = [][]int{
	{3, 3, 3, 3, 3, 3, 3, 3},
	{1, 1, 1, 1, 1, 1, 1, 1},
	{1, 2, 1, 2, 1, 2, 1, 1},
	{1, 1, 1, 1, 1, 1, 1, 1},
	{1, 2, 1, 2, 1, 2, 1, 1},
	{1, 1, 1, 1, 1, 1, 1, 1},
}

// ─────────────────────────────
// 【木のスプライト】(新規:8×8ドット、建物と同じパレットを使用)
// 上部( canopy )は屋根色(キー3)、下部( trunk )は壁色(キー1)
var treeSprite = [][]int{
	{0, 0, 0, 1, 1, 0, 0, 0},
	{0, 0, 1, 1, 1, 1, 0, 0},
	{0, 1, 1, 1, 1, 1, 1, 0},
	{0, 1, 1, 1, 1, 1, 1, 0},
	{0, 1, 1, 1, 1, 1, 1, 0},
	{0, 0, 0, 1, 1, 0, 0, 0},
	{0, 0, 0, 1, 1, 0, 0, 0},
	{0, 0, 0, 1, 1, 0, 0, 0},
}

// ─────────────────────────────
// 【月のスプライト】(8×8ドット)
// キー6を使用
// 満月
var moonFullSprite = [][]int{
	{0, 0, 6, 6, 6, 6, 0, 0},
	{0, 6, 6, 6, 6, 6, 6, 0},
	{6, 6, 6, 6, 6, 6, 6, 6},
	{6, 6, 6, 6, 6, 6, 6, 6},
	{6, 6, 6, 6, 6, 6, 6, 6},
	{6, 6, 6, 6, 6, 6, 6, 6},
	{0, 6, 6, 6, 6, 6, 6, 0},
	{0, 0, 6, 6, 6, 6, 0, 0},
}

// 半月(左側のみ表示)
var moonHalfSprite = [][]int{
	{0, 0, 6, 6, 0, 0, 0, 0},
	{0, 6, 6, 6, 0, 0, 0, 0},
	{6, 6, 6, 6, 0, 0, 0, 0},
	{6, 6, 6, 6, 0, 0, 0, 0},
	{6, 6, 6, 6, 0, 0, 0, 0},
	{6, 6, 6, 6, 0, 0, 0, 0},
	{0, 6, 6, 6, 0, 0, 0, 0},
	{0, 0, 6, 6, 0, 0, 0, 0},
}

// 三日月
var moonCrescentSprite = [][]int{
	{0, 0, 6, 6, 6, 6, 0, 0},
	{0, 0, 0, 6, 6, 6, 6, 0},
	{0, 0, 0, 0, 6, 6, 6, 6},
	{0, 0, 0, 0, 6, 6, 6, 6},
	{0, 0, 0, 6, 6, 6, 6, 6},
	{6, 6, 6, 6, 6, 6, 6, 6},
	{0, 6, 6, 6, 6, 6, 6, 0},
	{0, 0, 6, 6, 6, 6, 0, 0},
}

// ─────────────────────────────
// 描画用関数

// drawSprite: 指定位置にスプライトを描画(layer毎にシェーディング適用)
// layer: 0 = 奥(または背景)、1 = 中間、2 = 手前
func drawSprite(c *p5go.Canvas, sprite [][]int, x, y, scale float64, layer int) {
	layerShading := [3]float64{1.0, 0.8, 0.6}
	shading := layerShading[layer]
	for i := 0; i < len(sprite); i++ {
		for j := 0; j < len(sprite[i]); j++ {
			pixel := sprite[i][j]
			if pixel != 0 {
				if color, exists := palette[pixel]; exists {
					c.Fill(float64(color[0])*shading, float64(color[1])*shading, float64(color[2])*shading)
					c.Rect(x+float64(j)*scale, y+float64(i)*scale, scale, scale)
				}
			}
		}
	}
}

// drawNightSky: 夜空と星を描画
func drawNightSky(c *p5go.Canvas) {
	c.Background(30, 30, 40)
	for i := 0; i < STAR_COUNT; i++ {
		x := rand.Float64() * CANVAS_WIDTH
		y := rand.Float64() * (CANVAS_HEIGHT / 2)
		starSize := rand.Float64()*2 + 1
		brightness := 180 + rand.Intn(75)
		c.Fill(float64(brightness), float64(brightness), float64(brightness))
		c.Ellipse(x, y, starSize, starSize)
	}
}

// generateCityscape: レイヤー毎に建物群を描画
func generateCityscape(c *p5go.Canvas) {
	layers := 3
	// 建物スプライト(木は別扱い)
	sprites := [][][]int{
		highBuildingSprite1,
		commercialBuildingSprite,
		triangleBuildingSprite,
		towerSprite,
	}
	for layer := layers - 1; layer >= 0; layer-- {
		buildingCount := CANVAS_WIDTH / BUILDING_BASE_WIDTH
		for i := 0; i < buildingCount; i++ {
			x := float64(i)*BUILDING_BASE_WIDTH + float64(rand.Intn(20)-10)
			y := BASE_Y - float64(layer*30)
			scale := float64(SPRITE_SCALE)
			// 16ドット高さのスプライトを、下端が y に合うように描画
			selectedSprite := sprites[rand.Intn(len(sprites))]
			drawSprite(c, selectedSprite, x, y-16*scale, scale, layer)
		}
	}
}

// generateTrees: 地面に小さな木を描画(手前レイヤー)
// ここでは木スプライト(8×8)を TREE_SCALE で描画し、下端を地面(BASE_Y)に合わせます。
func generateTrees(c *p5go.Canvas) {
	for i := 0; i < TREE_COUNT; i++ {
		x := rand.Float64() * CANVAS_WIDTH
		y := BASE_Y - float64(len(treeSprite))*TREE_SCALE
		drawSprite(c, treeSprite, x, y, TREE_SCALE, 2)
	}
}

// generateMoon: 上空に月をドット絵で表示(3種類のうちランダムに選択)
func generateMoon(c *p5go.Canvas) {
	moonSprites := [][][]int{
		moonFullSprite,
		moonHalfSprite,
		moonCrescentSprite,
	}
	selectedMoon := moonSprites[rand.Intn(len(moonSprites))]
	moonWidth := len(selectedMoon[0])
	moonHeight := len(selectedMoon)
	// x はキャンバス右端に収まるように、y は上半分に配置
	x := rand.Float64() * (CANVAS_WIDTH - float64(moonWidth)*MOON_SCALE)
	y := rand.Float64() * ((CANVAS_HEIGHT / 2) - float64(moonHeight)*MOON_SCALE)
	drawSprite(c, selectedMoon, x, y, MOON_SCALE, 0)
}

// ─────────────────────────────
// main
func main() {
	p5go.Run("#canvas-detail",
		p5go.Setup(func(c *p5go.Canvas) {
			c.CreateCanvas(CANVAS_WIDTH, CANVAS_HEIGHT)
			c.NoStroke()
		}),
		p5go.Draw(func(c *p5go.Canvas) {
			c.NoLoop()
			drawNightSky(c)
			generateMoon(c)
			generateCityscape(c)
			generateTrees(c)
		}),
	)
	select {}
}