import React, { Component } from 'react'
import {
    Button,
    Cascader,
    Form,
    Input,
    InputNumber,
    Radio,
    Spin,
    Select,
    Row,
    Col,
    Tag,
    Alert,
    Tooltip,
} from 'antd'
import { AntIcon, Auth } from 'components'
import { cloneDeep, isEqual } from 'lodash'
import getDictData from 'util/dic'
import { api } from 'common/api'
import { CITY } from 'util/global'
import auth from 'components/authorized/handler'
import store from 'store'

const { getState } = store

const initialValues = {
    type: 1,
    industry: 1,
}

const labelCol = { flex: '150px' }
const wrapperCol = { flex: '1' }

export default class form extends Component {
    state = {
        // 加载状态
        loading: true,
        codes: {
            houseType: [],
            houseIndustry: [],
        },
        options: {
            areaTree: [],
            projects: [],
            zones: [],
        },

        houseCode: '',
        showIndustry: false,
    }

    theme = getState('layout').theme

    nav = getState('nav').nav

    // 表单实例
    form = React.createRef()

    iconSelector = React.createRef()

    // 初始化数据
    record = {}

    shouldComponentUpdate(props, state) {
        return !isEqual(this.state, state)
    }

    /**
     * mount后回调
     */
    componentDidMount() {
        if (this.props.onRef) {
            this.props.onRef(this)
        }
        this.fillData({
            record: this.props.record,
        })

        console.log(this.nav)
    }

    componentWillUnmount() {
        if (this.map) this.map.destroy()
    }

    /**
     * 填充数据
     * 可以在设置this.record之后对其作出数据结构调整
     * [异步,必要]
     * @param {*} params
     */
    async fillData(params) {
        this.record = cloneDeep(params.record)
        //#region 从后端转换成前段所需格式
        await this.initMap()
        const options = { ...this.state.options }
        const { data: areaTree } = await api.getAreaTree()
        options.areaTree = areaTree
        // 有数据
        if (this.record) {
            const { type, areaCode } = this.record
            // areaCode需要从字符串转为数组
            this.record.areaCode = [
                areaCode.substr(0, 4),
                areaCode.substr(0, 6),
                areaCode.substr(0, 9),
                areaCode,
            ]
            switch (areaTree[0].adCode.length) {
                case 6:
                    this.record.areaCode = this.record.areaCode.slice(1)
                    break
                case 9:
                    this.record.areaCode = this.record.areaCode.slice(2)
                    break
                default:
                    break
            }
            // 获取项目和片区列表
            const data = await this.getProjectsAndZones({
                areaCode: this.record.areaCode,
                type,
            })
            Object.assign(options, data)
            // 定位
            const position = [this.record.lng, this.record.lat]
            this.setMarker(position)
            this.map.setCenter(position)
        }
        const codes = await getDictData('house_type', 'house_industry')

        this.setState({
            codes,
            options,
        })

        this.showHouseCode()
        //#endregion
        this.form.current.setFieldsValue(this.record)

        this.setState({
            loading: false,
        })
    }

    /**
     * 获取数据
     * 可以对postData进行数据结构调整
     * [异步,必要]
     * @returns
     */
    async getData() {
        const form = this.form.current

        const valid = await form.validateFields()
        if (valid) {
            const postData = form.getFieldsValue()
            //#region 从前段转换后端所需格式
            if (postData.areaCode) {
                postData.areaCode = postData.areaCode[postData.areaCode.length - 1]
            }
            //#endregion
            return postData
        }
    }

    //#region 自定义方法
    initMap() {
        // eslint-disable-next-line no-undef
        const amap = AMap

        return new Promise(resolve => {
            const city = CITY

            const district = new amap.DistrictSearch({
                subdistrict: 0,
                extensions: 'all',
                level: 'city',
            })

            district.search(city, (status, result) => {
                const bounds = result.districtList[0].boundaries,
                    mask = []
                for (let i = 0; i < bounds.length; i += 1) {
                    mask.push([bounds[i]])
                }

                const geocoder = new amap.Geocoder({ city })
                geocoder.getLocation(city, (status, result) => {
                    if (status !== 'complete' || !(result.geocodes && result.geocodes.length))
                        return

                    this.citycode = result.geocodes[0].addressComponent.citycode

                    this.map = new amap.Map(this.refs.map, {
                        mask,
                        zoom: 12,
                        center: result.geocodes[0].location,
                        mapStyle: `amap://styles/${this.theme}`,
                    })

                    this.map.on('click', e => {
                        this.setMarker(e.lnglat, geocoder)
                    })

                    this.map.on('complete', () => {
                        this.map.setFitView()
                        this.map.setZoom(12)

                        for (const path of bounds) {
                            new amap.Polyline({
                                path,
                                strokeColor: '#ccc',
                                strokeWeight: 4,
                                map: this.map,
                            })
                        }

                        resolve()
                    })

                    const auto = new amap.AutoComplete({
                        input: this.refs['map-search'].input,
                        city,
                        citylimit: true,
                    })

                    const placeSearch = new amap.PlaceSearch({
                        city,
                        citylimit: true,
                        pageSize: 1,
                    })

                    auto.on('select', ({ poi: { name: keywords, adcode } }) => {
                        placeSearch.search(keywords, async (status, result) => {
                            const {
                                poiList: { pois },
                            } = result
                            for (const poi of pois) {
                                await this.setMarker(poi.location, geocoder)
                                this.map.setCenter(poi.location)
                            }
                        })
                    })
                })
            })
        })
    }

    setMarker(position, geocoder) {
        const set = position => {
            if (this.marker) {
                this.marker.setPosition(position)
            } else {
                this.marker = new amap.Marker({
                    map: this.map,
                    icon: '//a.amap.com/jsapi_demos/static/demo-center/icons/poi-marker-default.png',
                    position,
                    offset: new amap.Pixel(-13, -30),
                })
            }
        }

        // eslint-disable-next-line no-undef
        const amap = AMap

        return new Promise((resolve, reject) => {
            if (geocoder) {
                geocoder.getAddress(position, (status, result) => {
                    if (status === 'complete' && result.regeocode) {
                        if (result.regeocode.addressComponent.citycode !== this.citycode) {
                            // 如果选到了别的城市,则中断
                            return
                        }
                        this.setPosition(result.regeocode.formattedAddress, position)

                        set(position)
                        resolve(position)
                    } else {
                        console.error('根据经纬度查询地址失败')

                        reject()
                    }
                })
            } else {
                set(position)
                resolve(position)
            }
        })
    }

    setPosition(address, { lng, lat }) {
        this.form.current.setFieldsValue({
            address,
            lng,
            lat,
        })
    }

    async getProjectsAndZones({ areaCode, type } = {}, mode = ['projects', 'zones']) {
        if (!areaCode || !type) {
            const value = this.form.current.getFieldsValue()
            areaCode = value.areaCode
            type = value.type
        }

        if (!(areaCode && areaCode.length > 0 && areaCode[areaCode.length - 1].length === 12))
            return null

        try {
            const result = {}

            if (mode.includes('projects')) {
                const { data: projects } = await api.houseProjectList({
                    areaCode: areaCode[areaCode.length - 1],
                    type,
                })
                result.projects = projects
            }
            if (mode.includes('zones')) {
                const { data: zones } = await api.houseZoneList({
                    areaCode: areaCode[areaCode.length - 1],
                })
                result.zones = zones
            }

            return result
        } catch {
            return null
        }
    }

    async getCodeNo(projectId) {
        this.setState({ loading: true })
        const { data: no } = await api.houseCodeNo({ projectId })
        this.form.current.setFieldsValue({
            no,
        })
        this.setState({ loading: false })
    }

    showHouseCode(values) {
        if (this.record) {
            this.setState({
                houseCode: this.record.houseCode,
            })
        } else if (values) {
            const { type, industry, areaCode, projectId, no } = values
            if (
                areaCode &&
                areaCode.length > 0 &&
                areaCode[areaCode.length - 1].length === 12 &&
                projectId &&
                no
            ) {
                let houseCode = areaCode[areaCode.length - 1]
                const projectSort = this.state.options.projects.find(p => p.id === projectId).sort
                houseCode += projectSort.toString().padStart(3, '0')
                houseCode += no.toString().padStart(3, '0')
                if (type == 1) {
                    this.setState({ houseCode })
                } else {
                    if (!industry) {
                        this.setState({ houseCode: '' })
                    } else {
                        const tag = this.state.codes.houseIndustry.find(p => p.code == industry)
                            .extCode.tag
                        houseCode += `-${tag}`
                        this.setState({ houseCode })
                    }
                }
            } else {
                this.setState({ houseCode: '' })
            }
        }
    }

    async onValuesChange(changedValues, allValues) {
        const form = this.form.current
        // 房屋性质
        if (changedValues.hasOwnProperty('type')) {
            this.setState({
                showIndustry: changedValues.type == 2,
                loading: true,
            })
            const data = await this.getProjectsAndZones()
            form.setFieldsValue({ projectId: undefined })
            this.setState({
                options: {
                    ...this.state.options,
                    ...data,
                },
                loading: false,
            })
            this.showHouseCode(form.getFieldsValue())
        }

        // 所属区域
        else if (changedValues.hasOwnProperty('areaCode')) {
            const flag = auth({ houseCode: 'getNextNoByCode' })
            if (flag) {
                this.setState({ loading: true })
                const data = await this.getProjectsAndZones()
                form.setFieldsValue({ projectId: undefined, zoneId: undefined })
                this.setState({
                    options: {
                        ...this.state.options,
                        ...data,
                    },
                    loading: false,
                })
                this.showHouseCode(form.getFieldsValue())
            }
        }

        // 所属项目
        else if (changedValues.hasOwnProperty('projectId')) {
            await this.getCodeNo(changedValues.projectId)
            this.showHouseCode(form.getFieldsValue())
        }

        // 所属行业
        else if (changedValues.hasOwnProperty('industry')) {
            this.showHouseCode(allValues)
        }

        // 编号
        else if (changedValues.hasOwnProperty('no')) {
            this.showHouseCode(allValues)
        }
    }

    async onReloadProjectsOrZones(mode) {
        this.setState({ loading: true })
        const data = await this.getProjectsAndZones({}, [mode])
        this.setState({
            options: {
                ...this.state.options,
                ...data,
            },
            loading: false,
        })
    }
    //#endregion

    render() {
        const { loading, codes, options, showIndustry, houseCode } = this.state

        return (
            <Form
                initialValues={initialValues}
                ref={this.form}
                // labelCol={labelCol}
                // wrapperCol={wrapperCol}
                onValuesChange={(changedValues, allValues) =>
                    this.onValuesChange(changedValues, allValues)
                }
                layout="vertical"
            >
                <Spin spinning={loading} indicator={<AntIcon type="loading" />}>
                    <Row gutter={16}>
                        <Col span={10}>
                            <div className="yo-map-container">
                                <div className="yo-map--search">
                                    <Input.Search
                                        allowClear
                                        placeholder="请输入关键字"
                                        ref="map-search"
                                    />
                                </div>
                                <div className="h-700" ref="map"></div>
                            </div>
                        </Col>
                        <Col span={14}>
                            <Form.Item
                                label="房屋性质"
                                name="type"
                                rules={[{ required: true, message: '请选择房屋性质' }]}
                            >
                                <Radio.Group disabled={!!this.record} buttonStyle="solid">
                                    {codes.houseType.map(item => (
                                        <Radio.Button key={item.code} value={+item.code}>
                                            {item.value}
                                        </Radio.Button>
                                    ))}
                                </Radio.Group>
                            </Form.Item>
                            {showIndustry && (
                                <Form.Item
                                    label="所属行业、系统"
                                    name="industry"
                                    rules={[{ required: true, message: '请选择所属行业、系统' }]}
                                >
                                    <Radio.Group disabled={!!this.record} buttonStyle="solid">
                                        {codes.houseIndustry.map(item => (
                                            <Radio.Button key={item.code} value={+item.code}>
                                                {item.value}
                                            </Radio.Button>
                                        ))}
                                    </Radio.Group>
                                </Form.Item>
                            )}
                            <Form.Item label="房屋编码" required className="mb-none">
                                <Row gutter={16}>
                                    <Col flex="100%">
                                        <Form.Item
                                            name="areaCode"
                                            rules={[
                                                {
                                                    required: true,
                                                    message: '请选择房屋所在区域',
                                                },
                                            ]}
                                        >
                                            <Cascader
                                                allowClear={false}
                                                displayRender={labels => labels.join(' - ')}
                                                fieldNames={{
                                                    label: 'name',
                                                    value: 'code',
                                                    children: 'children',
                                                }}
                                                options={options.areaTree}
                                                expandTrigger="hover"
                                            />
                                        </Form.Item>
                                    </Col>
                                    <Col flex="1">
                                        <Row gutter={8}>
                                            <Col flex="1">
                                                <Form.Item
                                                    name="projectId"
                                                    rules={[
                                                        { required: true, message: '请选择项目' },
                                                    ]}
                                                >
                                                    <Select placeholder="请选择项目">
                                                        {options.projects.map(item => (
                                                            <Select.Option
                                                                key={item.id}
                                                                value={item.id}
                                                            >
                                                                {item.name}({item.note})
                                                            </Select.Option>
                                                        ))}
                                                    </Select>
                                                </Form.Item>
                                            </Col>
                                            <Auth auth="houseProjectInfo:page">
                                                <Col>
                                                    <Button.Group>
                                                        <Button
                                                            onClick={() =>
                                                                window.openContentWindowByMenuName(
                                                                    'bs_house_project_manage'
                                                                )
                                                            }
                                                        >
                                                            项目管理
                                                        </Button>
                                                        <Tooltip
                                                            placement="top"
                                                            title="重新加载项目列表"
                                                        >
                                                            <Button
                                                                icon={<AntIcon type="reload" />}
                                                                onClick={() =>
                                                                    this.onReloadProjectsOrZones(
                                                                        'projects'
                                                                    )
                                                                }
                                                            ></Button>
                                                        </Tooltip>
                                                    </Button.Group>
                                                </Col>
                                            </Auth>
                                        </Row>
                                    </Col>
                                    <Col flex="1">
                                        <Form.Item
                                            name="no"
                                            rules={[{ required: true, message: '请输入房屋序号' }]}
                                        >
                                            <InputNumber
                                                formatter={value => value.padStart(3, '0')}
                                                max={999}
                                                min={1}
                                                precision={0}
                                                step={1}
                                                className="w-100-p"
                                                placeholder="请输入房屋序号"
                                            />
                                        </Form.Item>
                                    </Col>
                                    {showIndustry && <Col>-</Col>}
                                </Row>
                            </Form.Item>
                            {houseCode && (
                                <Form.Item>
                                    <Tag
                                        color="purple"
                                        style={{
                                            fontSize: '24px',
                                            fontWeight: 'bold',
                                            letterSpacing: '10px',
                                            padding: '12px',
                                        }}
                                    >
                                        {houseCode}
                                    </Tag>
                                </Form.Item>
                            )}
                            <Alert
                                message={<b>房屋编码说明</b>}
                                description={
                                    <>
                                        房屋所在市
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        —县（市、区）
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        —街道（乡、镇）
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        —社区、居（村）委会）
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        —项目
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        —实物幢序号
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />
                                        <AntIcon type="border" />。
                                        根据省厅既有建筑物编号规则，房屋所在区域编号按照市、县（市、区）、街道（乡、镇）、社区、居（村）委会）、项目分类，其中市、县（市）区部分按照《中华人民共和国行政区划代码》（GB2260）标准编码，街道（乡、镇）按《县以下行政区划代码编码规则》（GB10114-88）标准编码，社区、居（村）委会部分按照统计局提供编码设定。各地上报各街道社区名称后，上述编号由系统自动生成。
                                        <br />
                                        各社区下辖项目由各地负责统一编码，住宅项目序号一般一个小区一号，采用3位数，001号起编，范围为001~999。实物幢序号由各地负责统一编码，以幢为单位，采用3位数，001号起编，范围为001~999。
                                    </>
                                }
                            />
                            <br />
                            <Form.Item label="所属片区" required>
                                <Row gutter={8}>
                                    <Col flex="1">
                                        <Form.Item
                                            name="zoneId"
                                            rules={[{ required: true, message: '请选择所属片区' }]}
                                            noStyle
                                        >
                                            <Select
                                                placeholder="请选择所属片区"
                                                className="w-100-p"
                                            >
                                                {options.zones.map(item => (
                                                    <Select.Option key={item.id} value={item.id}>
                                                        {item.name}
                                                    </Select.Option>
                                                ))}
                                            </Select>
                                        </Form.Item>
                                    </Col>
                                    <Auth auth="houseZone:page">
                                        <Col>
                                            <Button.Group>
                                                <Button
                                                    onClick={() =>
                                                        window.openContentWindowByMenuName(
                                                            'bs_house_zone_manage'
                                                        )
                                                    }
                                                >
                                                    片区管理
                                                </Button>
                                                <Tooltip placement="top" title="重新加载片区列表">
                                                    <Button
                                                        icon={<AntIcon type="reload" />}
                                                        onClick={() =>
                                                            this.onReloadProjectsOrZones('zones')
                                                        }
                                                    ></Button>
                                                </Tooltip>
                                            </Button.Group>
                                        </Col>
                                    </Auth>
                                </Row>
                            </Form.Item>
                            <Form.Item
                                label="房屋地址"
                                name="address"
                                rules={[{ required: true, message: '请输入房屋地址' }]}
                            >
                                <Input
                                    autoComplete="off"
                                    placeholder="请输入房屋地址或在地图上选择地点"
                                />
                            </Form.Item>
                            <Form.Item label="地理坐标" required>
                                <Row gutter={16}>
                                    <Col span={12}>
                                        <Form.Item
                                            name="lng"
                                            className="mb-none"
                                            rules={[
                                                { required: true, message: '请在地图中选择坐标' },
                                            ]}
                                        >
                                            <Input
                                                disabled
                                                placeholder="请在地图中选择坐标"
                                                prefix="经度"
                                            />
                                        </Form.Item>
                                    </Col>
                                    <Col span={12}>
                                        <Form.Item
                                            name="lat"
                                            className="mb-none"
                                            rules={[
                                                { required: true, message: '请在地图中选择坐标' },
                                            ]}
                                        >
                                            <Input
                                                disabled
                                                placeholder="请在地图中选择坐标"
                                                prefix="纬度"
                                            />
                                        </Form.Item>
                                    </Col>
                                </Row>
                            </Form.Item>
                        </Col>
                    </Row>
                </Spin>
            </Form>
        )
    }
}
