<script lang="ts">
    import type { CSSProperties, PropType } from 'vue'
    import { computed, defineComponent, provide, ref, unref, watch } from 'vue'

    import { useDesign } from '/@/hooks/web/useDesign'
    import { propTypes } from '/@/utils/propTypes'
    import { omit } from 'lodash-es'
    import { PageHeader } from 'ant-design-vue'
    import { useContentHeight } from '/@/hooks/web/useContentHeight'
    import { PageWrapperFixedHeightKey } from '..'
    import PageFooter from './PageFooter.vue'

    export default defineComponent({
        name: 'PageWrapper',
        components: { PageFooter, PageHeader },
        inheritAttrs: false,
        props: {
            title: propTypes.string,
            dense: propTypes.bool,
            ghost: propTypes.bool,
            content: propTypes.string,
            contentStyle: {
                type: Object as PropType<CSSProperties>,
            },
            contentBackground: propTypes.bool,
            contentFullHeight: propTypes.bool,
            contentClass: propTypes.string,
            fixedHeight: propTypes.bool,
            upwardSpace: propTypes.oneOfType([propTypes.number, propTypes.string]).def(0),
        },
        setup(props, { slots, attrs }) {
            const wrapperRef = ref(null)
            const headerRef = ref(null)
            const contentRef = ref(null)
            const footerRef = ref(null)
            const { prefixCls } = useDesign('page-wrapper')

            provide(
                PageWrapperFixedHeightKey,
                computed(() => props.fixedHeight),
            )

            const getIsContentFullHeight = computed(() => {
                return props.contentFullHeight
            })

            const getUpwardSpace = computed(() => props.upwardSpace)
            const { redoHeight, setCompensation, contentHeight } = useContentHeight(
                getIsContentFullHeight,
                wrapperRef,
                [headerRef, footerRef],
                [contentRef],
                getUpwardSpace,
            )
            setCompensation({ useLayoutFooter: true, elements: [footerRef] })

            const getClass = computed(() => {
                return [
                    prefixCls,
                    {
                        [`${prefixCls}--dense`]: props.dense,
                    },
                    attrs.class ?? {},
                ]
            })

            const getShowHeader = computed(
                () => props.content || slots?.headerContent || props.title || getHeaderSlots.value.length,
            )

            const getShowFooter = computed(() => slots?.leftFooter || slots?.rightFooter)

            const getHeaderSlots = computed(() => {
                return Object.keys(omit(slots, 'default', 'leftFooter', 'rightFooter', 'headerContent'))
            })

            const getContentStyle = computed((): CSSProperties => {
                const { contentFullHeight, contentStyle, fixedHeight } = props
                if (!contentFullHeight) {
                    return { ...contentStyle }
                }

                const height = `${unref(contentHeight)}px`
                return {
                    ...contentStyle,
                    minHeight: height,
                    ...(fixedHeight ? { height } : {}),
                }
            })

            const getContentClass = computed(() => {
                const { contentBackground, contentClass } = props
                return [
                    `${prefixCls}-content`,
                    contentClass,
                    {
                        [`${prefixCls}-content-bg`]: contentBackground,
                    },
                ]
            })

            watch(
                () => [getShowFooter.value],
                () => {
                    redoHeight()
                },
                {
                    flush: 'post',
                    immediate: true,
                },
            )

            return {
                getContentStyle,
                wrapperRef,
                headerRef,
                contentRef,
                footerRef,
                getClass,
                getHeaderSlots,
                prefixCls,
                getShowHeader,
                getShowFooter,
                omit,
                getContentClass,
            }
        },
    })
</script>

<template>
    <div :class="getClass" ref="wrapperRef">
        <PageHeader :ghost="ghost" :title="title" v-bind="omit($attrs, 'class')" ref="headerRef" v-if="getShowHeader">
            <template #default>
                <template v-if="content">
                    {{ content }}
                </template>
                <slot name="headerContent" v-else></slot>
            </template>
            <template #[item]="data" v-for="item in getHeaderSlots">
                <slot :name="item" v-bind="data || {}"></slot>
            </template>
        </PageHeader>

        <div class="overflow-hidden" :class="getContentClass" :style="getContentStyle" ref="contentRef">
            <slot></slot>
        </div>

        <PageFooter v-if="getShowFooter" ref="footerRef">
            <template #left>
                <slot name="leftFooter"></slot>
            </template>
            <template #right>
                <slot name="rightFooter"></slot>
            </template>
        </PageFooter>
    </div>
</template>

<style lang="less">
    @prefix-cls: ~'@{namespace}-page-wrapper';

    .@{prefix-cls} {
        position: relative;

        .@{prefix-cls}-content {
            margin: 16px;
        }

        .ant-page-header {
            &:empty {
                padding: 0;
            }
        }

        &-content-bg {
            background-color: @component-background;
        }

        &--dense {
            .@{prefix-cls}-content {
                margin: 0;
            }
        }
    }
</style>
