import { Input, Select, Upload } from '@/components/ui'
import Button from '@/components/ui/Button'
import { FormContainer, FormItem } from '@/components/ui/Form'
import Notification from '@/components/ui/Notification'
import toast from '@/components/ui/toast'
import { AVATAR_URL } from '@/constants/app.constant'
import { useStoreActions, useStoreState } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import dayjs from 'dayjs'
import { Field, Form, Formik } from 'formik'

import { useEffect, useRef, useState } from 'react'
import {
  CircleStencil,
  Cropper,
  CropperPreview,
  CropperPreviewRef,
  CropperRef,
} from 'react-advanced-cropper'
import 'react-advanced-cropper/dist/style.css'
import {
  FaFacebookMessenger,
  FaEnvelope,
  FaTrashAlt,
  FaUserCircle,
  FaPhone,
  FaPlus,
  FaHome,
  FaUniversity,
} from 'react-icons/fa'
import * as Yup from 'yup'
import isEmpty from 'lodash/isEmpty'
import { ProfileDto, UpdateProfileDto } from '@/proxy/account/models'
import { getProfile, updateProfile } from '@/services/account.service'
import { CountryDto, getCountry } from '@/services/home.service'
import { SelectBoxOption } from '@/types/shared'
import { useSetting } from '@/utils/hooks/useSetting'

const schema = Yup.object().shape({
  name: Yup.string().min(3).max(50).required(),
  surname: Yup.string().min(3).max(50).required(),
})

const General = () => {
  const [loading, setLoading] = useState(true)
  const [profileData, setProfileData] = useState<ProfileDto>()
  const [formData, setFormData] = useState<UpdateProfileDto>()
  const [image, setImage] = useState<string | undefined>()
  const [countries, setCountries] = useState<CountryDto[]>([])

  const auth = useStoreState((state) => state.auth)
  const { setUser } = useStoreActions((actions) => actions.auth.user)

  const { setting } = useSetting()
  const isEmailUpdateEnabled = setting('Abp.Identity.User.IsEmailUpdateEnabled')

  const { translate } = useLocalization()
  const cropperRef = useRef<CropperRef>(null)
  const previewRef = useRef<CropperPreviewRef>(null)

  const fetchData = async () => {
    setLoading(true)
    const [response, countryResponse] = await Promise.all([getProfile(), getCountry()])
    setProfileData(response.data)
    setCountries(countryResponse.data)
    setImage(auth.user.avatar)
    setFormData({
      name: response.data.name,
      surname: response.data.surname,
    })
    setLoading(false)
  }

  useEffect(() => {
    if (isEmpty(profileData)) {
      fetchData()
    }
  }, [])

  const onChooseImage = async (file: File[]) => {
    if (file[0]) {
      setImage(URL.createObjectURL(file[0]))
    } else {
      setImage(undefined)
    }
  }

  const beforeUpload = (files: FileList | null, fileList: File[]) => {
    let valid: string | boolean = true

    const allowedFileType = ['image/jpeg', 'image/png', 'image/gif']
    const maxFileSize = 2000000

    if (fileList.length >= 1) {
      return `Sadece bir dosya seçebilirsiniz`
    }

    if (files) {
      for (const f of files) {
        if (!allowedFileType.includes(f.type)) {
          valid = '.jpg, .jpeg, .gif veya .png yükleyebilirsiniz'
        } else if (f.size >= maxFileSize) {
          valid = 'En fazla 2mb dosya yükleyebilirsiniz'
        }
      }
    }

    return valid
  }

  const onFormSubmit = async (
    values: UpdateProfileDto,
    setSubmitting: (isSubmitting: boolean) => void,
  ) => {
    const avatar = await getCroppedAvatar()
    const resp = await updateProfile({
      name: values.name,
      surname: values.surname,
      avatar: avatar ? new File([avatar], 'avatar') : undefined,
    })
    if (resp.status === 200) {
      setUser({
        ...auth.user,
        name: `${resp.data.name} ${resp.data.surname}`.trim(),
        avatar: AVATAR_URL(auth.user.id, auth.tenant.tenantId) + `?${dayjs().unix()}`,
      })

      toast.push(<Notification title={'Profil güncellendi'} type="success" />, {
        placement: 'top-end',
      })
    } else {
      toast.push(<Notification title={resp?.error?.message} type="danger" />, {
        placement: 'top-end',
      })
    }
    setSubmitting(false)
  }

  const getCroppedAvatar = () =>
    new Promise<Blob | null>((resolve, reject) => {
      const canvas = cropperRef.current?.getCanvas({
        minHeight: 100,
        minWidth: 100,
        maxHeight: 300,
        maxWidth: 300,
      })
      if (canvas) {
        canvas.toBlob((blob) => {
          if (blob) {
            resolve(blob)
          } else {
            reject()
          }
        }, 'image/jpeg')
      } else {
        resolve(null)
      }
    })

  const getProfileExtraValue = (key: string) => {
    const extraProperties = profileData?.extraProperties
    const value =
      extraProperties?.[key] ?? extraProperties?.[`${key.charAt(0).toLowerCase()}${key.slice(1)}`]

    return typeof value === 'string' || typeof value === 'number' ? String(value) : undefined
  }

  const getSelectValue = (options: SelectBoxOption[], value?: string) => {
    if (!value) {
      return null
    }

    return options.find((option) => option.value === value) ?? { value, label: value }
  }

  const nationalityOptions: SelectBoxOption[] = countries.map((country) => ({
    value: country.name,
    label: country.name,
  }))

  const educationOptions: SelectBoxOption[] = [
    {
      value: 'İlkokul',
      label: translate('::App.EducationLevel.Primary') || 'İlkokul',
    },
    {
      value: 'Ortaokul',
      label: translate('::App.EducationLevel.MiddleSchool') || 'Ortaokul',
    },
    {
      value: 'Lise',
      label: translate('::App.EducationLevel.HighSchool') || 'Lise',
    },
    {
      value: 'Ön Lisans',
      label: translate('::App.EducationLevel.Associate') || 'Ön Lisans',
    },
    {
      value: 'Lisans',
      label: translate('::App.EducationLevel.Bachelor') || 'Lisans',
    },
    {
      value: 'Yüksek Lisans',
      label: translate('::App.EducationLevel.Master') || 'Yüksek Lisans',
    },
    {
      value: 'Doktora',
      label: translate('::App.EducationLevel.PhD') || 'Doktora',
    },
  ]

  const bloodTypeOptions: SelectBoxOption[] = [
    { value: 'A Rh+', label: 'A Rh+' },
    { value: 'A Rh-', label: 'A Rh-' },
    { value: 'B Rh+', label: 'B Rh+' },
    { value: 'B Rh-', label: 'B Rh-' },
    { value: 'AB Rh+', label: 'AB Rh+' },
    { value: 'AB Rh-', label: 'AB Rh-' },
    { value: '0 Rh+', label: '0 Rh+' },
    { value: '0 Rh-', label: '0 Rh-' },
  ]

  if (loading) {
    return <></>
  }

  return (
    <Formik
      enableReinitialize
      initialValues={formData!}
      validationSchema={schema}
      onSubmit={(values, { setSubmitting }) => {
        setSubmitting(true)
        onFormSubmit(values, setSubmitting)
      }}
    >
      {({ touched, errors, isSubmitting, resetForm }) => {
        return (
          <Form>
            <FormContainer size="md">
              <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5 w-full">
                <div>
                  <h6 className="mb-4">
                    {translate('::Abp.Identity.User.UserInformation.ContactInformation')}
                  </h6>

                  <FormItem label={translate('::Abp.Account.EmailAddress')}>
                    <Input
                      type="text"
                      disabled={isEmailUpdateEnabled?.toLowerCase() !== 'true'}
                      prefix={<FaEnvelope className="text-xl" />}
                      value={profileData?.email}
                    ></Input>
                  </FormItem>
                  <FormItem
                    label={translate('::Abp.Identity.User.UserInformation.Name')}
                    invalid={(errors.name && touched.name) as boolean}
                    errorMessage={errors.name}
                  >
                    <Field
                      type="text"
                      autoComplete="off"
                      name="name"
                      placeholder="Name"
                      component={Input}
                      prefix={<FaUserCircle className="text-xl" />}
                    />
                  </FormItem>
                  <FormItem
                    label={translate('::Abp.Identity.User.UserInformation.Surname')}
                    invalid={(errors.surname && touched.surname) as boolean}
                    errorMessage={errors.surname}
                  >
                    <Field
                      type="text"
                      autoComplete="off"
                      name="surname"
                      placeholder="Last Name"
                      component={Input}
                      prefix={<FaUserCircle className="text-xl" />}
                    />
                  </FormItem>
                  <FormItem label={translate('::Abp.Identity.User.UserInformation.PhoneNumber')}>
                    <Input
                      type="text"
                      disabled
                      prefix={<FaPhone className="text-xl" />}
                      value={profileData?.phoneNumber}
                    ></Input>
                  </FormItem>
                  <FormItem label={translate('::RocketUsername')}>
                    <Input
                      type="text"
                      disabled
                      prefix={<FaFacebookMessenger className="text-xl" />}
                      value={profileData?.extraProperties?.['RocketUsername'] as string | undefined}
                    ></Input>
                  </FormItem>
                </div>

                <div>
                  <h6 className="mb-4">
                    {translate('::Abp.Identity.User.UserInformation.AdditionalInformation')}
                  </h6>

                  <FormItem label={translate('::Abp.Account.HomeAddress')}>
                    <Input
                      type="text"
                      disabled
                      prefix={<FaHome className="text-xl" />}
                      value={getProfileExtraValue('HomeAddress')}
                    ></Input>
                  </FormItem>
                  <FormItem label={translate('::Abp.Account.Nationality')}>
                    <Select<SelectBoxOption>
                      isDisabled
                      options={nationalityOptions}
                      value={getSelectValue(
                        nationalityOptions,
                        getProfileExtraValue('Nationality'),
                      )}
                    />
                  </FormItem>
                  <FormItem label={translate('::Abp.Account.EducationLevel')}>
                    <Select<SelectBoxOption>
                      isDisabled
                      options={educationOptions}
                      value={getSelectValue(
                        educationOptions,
                        getProfileExtraValue('EducationLevel'),
                      )}
                    />
                  </FormItem>
                  <FormItem label={translate('::Abp.Account.GraduationSchool')}>
                    <Input
                      type="text"
                      disabled
                      prefix={<FaUniversity className="text-xl" />}
                      value={getProfileExtraValue('GraduationSchool')}
                    ></Input>
                  </FormItem>
                  <FormItem label={translate('::Abp.Account.BloodType')}>
                    <Select<SelectBoxOption>
                      isDisabled
                      options={bloodTypeOptions}
                      value={getSelectValue(bloodTypeOptions, getProfileExtraValue('BloodType'))}
                    />
                  </FormItem>
                </div>

                <div>
                  <h6 className="mb-4">Avatar</h6>

                  <FormItem>
                    <div className="flex flex-col gap-4">
                      {image ? (
                        <Cropper
                          ref={cropperRef}
                          src={image}
                          onUpdate={(cropper) => {
                            setTimeout(() => {
                              previewRef.current?.update(cropper)
                            }, 100)
                          }}
                          className="cropper max-h-[300px] max-w-[300px]"
                          stencilComponent={CircleStencil}
                          minHeight={100}
                          minWidth={100}
                        />
                      ) : (
                        <img
                          className="cropper max-h-[300px] max-w-[300px]"
                          src={auth.user.avatar}
                        />
                      )}
                      <div className="flex items-start gap-4">
                        <div className="flex flex-col gap-2">
                          <Upload
                            className="cursor-pointer"
                            showList={false}
                            multiple={false}
                            uploadLimit={1}
                            beforeUpload={beforeUpload}
                            onChange={onChooseImage}
                          >
                            <Button
                              size="sm"
                              variant="default"
                              icon={<FaPlus />}
                              type="button"
                            ></Button>
                          </Upload>
                          <Button
                            size="sm"
                            variant="solid"
                            type="button"
                            icon={<FaTrashAlt />}
                            onClick={() => setImage(undefined)}
                          ></Button>
                        </div>
                        {image && (
                          <CropperPreview
                            ref={previewRef}
                            className="preview max-w-[100px] avatar-img avatar-circle"
                          />
                        )}
                      </div>
                    </div>
                  </FormItem>
                </div>
              </div>
              <div className="mt-4 ltr:text-right">
                <Button
                  size="sm"
                  className="ltr:mr-2 rtl:ml-2"
                  type="button"
                  onClick={() => resetForm()}
                >
                  {translate('::Cancel')}
                </Button>
                <Button size="sm" variant="solid" loading={isSubmitting} type="submit">
                  {isSubmitting ? translate('::Saving') : translate('::Save')}
                </Button>
              </div>
            </FormContainer>
          </Form>
        )
      }}
    </Formik>
  )
}

export default General
