import { Group, text, gravity, Color, LayoutSpec, vlayout, hlayout, layoutConfig, scroller, Text, ViewHolder, VMPanel, ViewModel, network, loge, HLayout, stack, image, Gravity, takeNonNull, Scroller, Image, View } from "doric";
import { colors } from "./utils";
import MovieData from './movie.json'

interface DoubanModel {
    count: number
    start: number
    total: number
    subjects: Array<{
        rating: {
            max: number,
            average: number,
            details: {
                "1": number,
                "2": number,
                "3": number,
                "4": number,
                "5": number,
            },
            stars: string
            min: number,
        }
        genres: string[],
        title: string
        casts: Array<{
            avatars: {
                small: string,
                large: string,
                medium: string,
            },
            name_en: string
            name: string
            alt: string
            id: string
        }>
        durations: string[]
        collect_count: number
        mainland_pubdate: string
        has_video: boolean
        original_title: string
        subtype: string
        directors: Array<{
            avatars: {
                small: string,
                large: string,
                medium: string,
            },
            name_en: string
            name: string
            alt: string
            id: string
        }>,
        pubdates: string[],

        year: string,
        images: {
            small: string,
            large: string,
            medium: string,
        }
        alt: string
        id: string
    }>
    title: string
}

interface MovieModel {
    doubanModel?: DoubanModel
    selectedIdx: number
    anchorPos: number
}

const frameWidth = 200
const frameHeight = 300
const padding = 20

class MovieVH extends ViewHolder {
    title!: Text
    gallery!: HLayout
    scrolled!: Scroller
    movieTitle!: Text
    movieYear!: Text
    anchor!: View
    build(root: Group) {
        vlayout(
            [
                this.title = text({
                    layoutConfig: {
                        widthSpec: LayoutSpec.MOST,
                        heightSpec: LayoutSpec.JUST,
                    },
                    textSize: 30,
                    textColor: Color.WHITE,
                    backgroundColor: colors[1],
                    textAlignment: gravity().center(),
                    height: 50,
                }),
                this.scrolled = scroller(
                    this.gallery = hlayout(
                        [],
                        {
                            layoutConfig: layoutConfig().fit(),
                            space: 0,
                            padding: {
                                top: 20,
                                left: 20,
                                right: 20,
                                bottom: 20,
                            },
                            gravity: Gravity.Center,
                        }),
                    {
                        layoutConfig: layoutConfig().most().configHeight(LayoutSpec.FIT),
                        backgroundColor: Color.parse("#eeeeee"),
                    }),
                vlayout(
                    [
                        stack(
                            [
                                this.anchor = image({
                                    imageBase64: "data:image/png;base64, ",
                                    layoutConfig: layoutConfig().just(),
                                    width: 30,
                                    height: 30,
                                }),
                            ],
                            {
                                layoutConfig: layoutConfig().fit().configWidth(LayoutSpec.MOST),
                            }
                        ),

                        this.movieTitle = text({
                            textSize: 20,
                        }),
                        this.movieYear = text({
                            textSize: 20,
                        }),
                    ],
                    {
                        layoutConfig: layoutConfig().fit().configWidth(LayoutSpec.MOST),
                        gravity: Gravity.Center
                    }),
            ],
            {
                layoutConfig: layoutConfig().most(),
                space: 0,
            }).in(root)
    }

}

class MovieVM extends ViewModel<MovieModel, MovieVH>{
    images: Map<number, Image> = new Map

    onAttached(state: MovieModel, vh: MovieVH) {
        network(context).get("https://douban.uieee.com/v2/movie/top250").then(ret => {
            this.updateState(state => state.doubanModel = JSON.parse(ret.data) as DoubanModel)
        })
        this.updateState(state => {
            state.anchorPos = padding + frameWidth / 2
            state.selectedIdx = 0
        })
        let scrollX = 0
        vh.scrolled.onScroll = (offset) => {
            if (offset.x < 0 || offset.x > (state.doubanModel?.count || 0) * frameWidth + padding * 2 - Environment.screenWidth) {
                return
            }
            const dx = offset.x - scrollX
            scrollX = offset.x
            const idx = Math.floor((offset.x + state.anchorPos - padding) / frameWidth)
            if (state.selectedIdx !== idx) {
                this.updateState(state => state.selectedIdx = idx)
            }
            takeNonNull(this.images.get(idx))(it => {
                const scale = (offset.x + state.anchorPos - (idx + 0.5) * frameWidth - padding) / (frameWidth / 2)
                it.scaleX = it.scaleY = 1.5 - Math.abs(scale * 0.5)
            })
            this.updateArrow()
        }
    }

    updateArrow() {
        takeNonNull(this.images.get(this.getState().selectedIdx))(it => {
            it.getLocationOnScreen(context).then(ret => {
                this.getViewHolder().anchor.centerX = ret.x + frameWidth / 2
            })
        })
    }

    onItemClicked(idx: number) {
        takeNonNull(this.images.get(this.getState().selectedIdx)?.superview)(it => {
            it.scaleX = it.scaleY = 1
        })
        takeNonNull(this.images.get(idx)?.superview)(it => {
            it.getLocationOnScreen(context).then(ret => {
                let anchor = this.getState().anchorPos
                if (ret.x < 0) {
                    this.getViewHolder().scrolled.scrollBy(context, { x: ret.x, y: 0 }, true)
                    anchor = frameWidth / 2
                } else if (ret.x > Environment.screenWidth - frameWidth) {
                    this.getViewHolder().scrolled.scrollBy(
                        context,
                        { x: ret.x - (Environment.screenWidth - frameWidth), y: 0 },
                        true)
                    anchor = Environment.screenWidth - frameWidth / 2
                } else {
                    anchor = ret.x + frameWidth / 2
                }
                this.updateState(state => {
                    state.selectedIdx = idx
                    state.anchorPos = anchor
                })
            })
        })
    }

    onBind(state: MovieModel, vh: MovieVH) {
        if (state.doubanModel) {
            vh.title.text = state.doubanModel.title
            vh.gallery.children.length = 0
            const vm = this
            state.doubanModel.subjects.forEach((e, idx) => {
                vh.gallery.addChild(stack(
                    [
                        image({
                            layoutConfig: layoutConfig().just().configAlignment(Gravity.Center),
                            width: frameWidth / 1.5,
                            height: frameHeight / 1.5,
                            imageUrl: e.images.large,
                            onClick: function () {
                                const v = (this as Image).superview
                                if (v == undefined) {
                                    return
                                }
                                vm.onItemClicked(idx)
                            },
                        }).also(it => {
                            this.images.set(idx, it)
                            if (state.selectedIdx == idx) {
                                it.scaleX = it.scaleY = 1.5
                            }
                        })
                    ],
                    {
                        layoutConfig: layoutConfig().just(),
                        width: frameWidth,
                        height: frameHeight,
                    }))
            })
            takeNonNull(state.doubanModel.subjects[state.selectedIdx])(it => {
                vh.movieTitle.text = it.title
                vh.movieYear.text = it.year
            })
        }
        vh.anchor.centerX = state.anchorPos
        this.updateArrow()
    }
}

@Entry
class SliderPanel extends VMPanel<MovieModel, MovieVH>{
    getViewModelClass() {
        return MovieVM
    }
    getViewHolderClass() {
        return MovieVH
    }

    getState() {
        return { selectedIdx: 0, anchorPos: Environment.screenWidth / 2, doubanModel: MovieData }
    }

}