import { track } from '@amplitude/analytics-browser'
import {
  ArrowSmRightIcon,
  PlusCircleIcon,
  XCircleIcon,
} from '@heroicons/react/outline'

import PencilIcon from '@heroicons/react/solid/PencilIcon'

import { Contract } from 'common/contract'
import { Group } from 'common/group'
import { Post } from 'common/post'
import { useEffect, useState } from 'react'
import { ReactNode } from 'react'
import { getPost } from 'web/lib/firebase/posts'
import { ContractSearch } from '../contract-search'
import { ContractCard } from '../contract/contract-card'

import Masonry from 'react-masonry-css'

import { Col } from '../layout/col'
import { Row } from '../layout/row'
import { SiteLink } from '../site-link'
import { GroupOverviewPost } from './group-overview-post'
import { getContractFromId } from 'web/lib/firebase/contracts'
import { groupPath, updateGroup } from 'web/lib/firebase/groups'
import { PinnedSelectModal } from '../pinned-select-modal'
import { Button } from '../button'
import { User } from 'common/user'
import { UserLink } from '../user-link'
import { EditGroupButton } from './edit-group-button'
import { JoinOrLeaveGroupButton } from './groups-button'
import { Linkify } from '../linkify'
import { ChoicesToggleGroup } from '../choices-toggle-group'
import { CopyLinkButton } from '../copy-link-button'
import { REFERRAL_AMOUNT } from 'common/economy'
import toast from 'react-hot-toast'
import { ENV_CONFIG } from 'common/envs/constants'
import { PostCard, PostCardList } from '../post-card'
import { LoadingIndicator } from '../loading-indicator'
import { useUser } from 'web/hooks/use-user'
import { CreatePost } from '../create-post'
import { Modal } from '../layout/modal'

const MAX_TRENDING_POSTS = 6

export function GroupOverview(props: {
  group: Group
  isEditable: boolean
  posts: Post[]
  aboutPost: Post | null
  creator: User
  user: User | null | undefined
  memberIds: string[]
}) {
  const { group, isEditable, posts, aboutPost, creator, user, memberIds } =
    props
  return (
    <Col className="pm:mx-10 gap-4 px-4 pb-12 pt-4 sm:pt-0">
      <GroupOverviewPinned
        group={group}
        posts={posts}
        isEditable={isEditable}
      />
      {(group.aboutPostId != null || isEditable) && (
        <>
          <SectionHeader label={'About'} href={'/post/' + group.slug} />
          <GroupOverviewPost
            group={group}
            isEditable={isEditable}
            post={aboutPost}
          />
        </>
      )}
      <SectionHeader label={'Trending'} />
      <ContractSearch
        user={user}
        defaultSort={'score'}
        noControls
        maxResults={MAX_TRENDING_POSTS}
        defaultFilter={'all'}
        additionalFilter={{ groupSlug: group.slug }}
        persistPrefix={`group-trending-${group.slug}`}
      />
      <GroupAbout
        group={group}
        creator={creator}
        isEditable={isEditable}
        user={user}
        memberIds={memberIds}
      />

      <GroupPosts group={group} posts={posts} />
    </Col>
  )
}

export function GroupPosts(props: { posts: Post[]; group: Group }) {
  const { posts, group } = props
  const [showCreatePost, setShowCreatePost] = useState(false)
  const user = useUser()

  const createPost = (
    <Modal size="xl" open={showCreatePost} setOpen={setShowCreatePost}>
      <div className="w-full bg-white py-10">
        <CreatePost group={group} />
      </div>
    </Modal>
  )

  const postList = (
    <div className=" align-start w-full items-start">
      <Row className="flex justify-between">
        <Col>
          <SectionHeader label={'Latest Posts'} />
        </Col>
        <Col>
          {user && (
            <Button
              className="btn-md"
              onClick={() => setShowCreatePost(!showCreatePost)}
            >
              Add a Post
            </Button>
          )}
        </Col>
      </Row>

      <div className="mt-2">
        <PostCardList posts={posts} />
        {posts.length === 0 && (
          <div className="text-center text-gray-500">No posts yet</div>
        )}
      </div>
    </div>
  )

  return showCreatePost ? createPost : postList
}

function GroupOverviewPinned(props: {
  group: Group
  posts: Post[]
  isEditable: boolean
}) {
  const { group, posts, isEditable } = props
  const [pinned, setPinned] = useState<JSX.Element[]>([])

  useEffect(() => {
    async function getPinned() {
      if (group.pinnedItems == null) {
        updateGroup(group, { pinnedItems: [] })
      } else {
        const itemComponents = await Promise.all(
          group.pinnedItems.map(async (element) => {
            if (element.type === 'post') {
              const post = await getPost(element.itemId)
              if (post) {
                return <PostCard post={post as Post} />
              }
            } else if (element.type === 'contract') {
              const contract = await getContractFromId(element.itemId)
              if (contract) {
                return <ContractCard contract={contract as Contract} />
              }
            }
          })
        )
        setPinned(
          itemComponents.filter(
            (element) => element != undefined
          ) as JSX.Element[]
        )
      }
    }
    getPinned()
  }, [group, group.pinnedItems])

  async function onSubmit(selectedItems: { itemId: string; type: string }[]) {
    await updateGroup(group, {
      pinnedItems: [
        ...group.pinnedItems,
        ...(selectedItems as { itemId: string; type: 'contract' | 'post' }[]),
      ],
    })
  }

  function onDeleteClicked(index: number) {
    const newPinned = group.pinnedItems.filter((item) => {
      return item.itemId !== group.pinnedItems[index].itemId
    })
    updateGroup(group, { pinnedItems: newPinned })
  }

  return isEditable || (group.pinnedItems && group.pinnedItems.length > 0) ? (
    <PinnedItems
      posts={posts}
      group={group}
      isEditable={isEditable}
      pinned={pinned}
      onDeleteClicked={onDeleteClicked}
      onSubmit={onSubmit}
      modalMessage={'Pin posts or markets to the overview of this group.'}
    />
  ) : (
    <LoadingIndicator />
  )
}

export function PinnedItems(props: {
  posts: Post[]
  isEditable: boolean
  pinned: JSX.Element[]
  onDeleteClicked: (index: number) => void
  onSubmit: (selectedItems: { itemId: string; type: string }[]) => void
  group?: Group
  modalMessage: string
}) {
  const {
    isEditable,
    pinned,
    onDeleteClicked,
    onSubmit,
    posts,
    group,
    modalMessage,
  } = props
  const [editMode, setEditMode] = useState(false)
  const [open, setOpen] = useState(false)

  return pinned.length > 0 || isEditable ? (
    <div>
      <Row className="mb-3 items-center justify-between">
        <SectionHeader label={'Pinned'} />
        {isEditable && (
          <Button
            color="gray"
            size="xs"
            onClick={() => {
              setEditMode(!editMode)
            }}
          >
            {editMode ? (
              'Done'
            ) : (
              <>
                <PencilIcon className="inline h-4 w-4" />
                Edit
              </>
            )}
          </Button>
        )}
      </Row>
      <div>
        <Masonry
          breakpointCols={{ default: 2, 768: 1 }}
          className="-ml-4 flex w-auto"
          columnClassName="pl-4 bg-clip-padding"
        >
          {pinned.length == 0 && !editMode && (
            <div className="flex flex-col items-center justify-center">
              <p className="text-center text-gray-400">
                No pinned items yet. Click the edit button to add some!
              </p>
            </div>
          )}
          {pinned.map((element, index) => (
            <div className="relative my-2">
              {element}

              {editMode && <CrossIcon onClick={() => onDeleteClicked(index)} />}
            </div>
          ))}
          {editMode && pinned.length < 6 && (
            <div className=" py-2">
              <Row
                className={
                  'relative gap-3 rounded-lg border-4 border-dotted p-2 hover:cursor-pointer hover:bg-gray-100'
                }
              >
                <button
                  className="flex w-full justify-center"
                  onClick={() => setOpen(true)}
                >
                  <PlusCircleIcon
                    className="h-12 w-12 text-gray-600"
                    aria-hidden="true"
                  />
                </button>
              </Row>
            </div>
          )}
        </Masonry>
      </div>
      <PinnedSelectModal
        open={open}
        group={group}
        posts={posts}
        setOpen={setOpen}
        title="Pin a post or market"
        description={
          <div className={'text-md my-4 text-gray-600'}>{modalMessage}</div>
        }
        onSubmit={onSubmit}
      />
    </div>
  ) : (
    <></>
  )
}

function SectionHeader(props: {
  label: string
  href?: string
  children?: ReactNode
}) {
  const { label, href, children } = props
  const content = (
    <>
      {label}{' '}
      <ArrowSmRightIcon
        className="mb-0.5 inline h-6 w-6 text-gray-500"
        aria-hidden="true"
      />
    </>
  )

  return (
    <Row className="mb-3 items-center justify-between">
      {href ? (
        <SiteLink
          className="text-xl"
          href={href}
          onClick={() => track('group click section header', { section: href })}
        >
          {content}
        </SiteLink>
      ) : (
        <span className="text-xl">{content}</span>
      )}
      {children}
    </Row>
  )
}

export function GroupAbout(props: {
  group: Group
  creator: User
  user: User | null | undefined
  isEditable: boolean
  memberIds: string[]
}) {
  const { group, creator, isEditable, user, memberIds } = props
  const anyoneCanJoinChoices: { [key: string]: string } = {
    Closed: 'false',
    Open: 'true',
  }
  const [anyoneCanJoin, setAnyoneCanJoin] = useState(group.anyoneCanJoin)
  function updateAnyoneCanJoin(newVal: boolean) {
    if (group.anyoneCanJoin == newVal || !isEditable) return
    setAnyoneCanJoin(newVal)
    toast.promise(updateGroup(group, { ...group, anyoneCanJoin: newVal }), {
      loading: 'Updating group...',
      success: 'Updated group!',
      error: "Couldn't update group",
    })
  }
  const postFix = user ? '?referrer=' + user.username : ''
  const shareUrl = `https://${ENV_CONFIG.domain}${groupPath(
    group.slug
  )}${postFix}`
  const isMember = user ? memberIds.includes(user.id) : false

  return (
    <>
      <Col className="gap-2 rounded-b bg-white p-2">
        <Row className={'flex-wrap justify-between'}>
          <div className={'inline-flex items-center'}>
            <div className="mr-1 text-gray-500">Created by</div>
            <UserLink
              className="text-neutral"
              name={creator.name}
              username={creator.username}
            />
          </div>
          {isEditable ? (
            <EditGroupButton className={'ml-1'} group={group} />
          ) : (
            user && (
              <Row>
                <JoinOrLeaveGroupButton
                  group={group}
                  user={user}
                  isMember={isMember}
                />
              </Row>
            )
          )}
        </Row>
        <div className={'block sm:hidden'}>
          <Linkify text={group.about} />
        </div>
        <Row className={'items-center gap-1'}>
          <span className={'text-gray-500'}>Membership</span>
          {user && user.id === creator.id ? (
            <ChoicesToggleGroup
              currentChoice={anyoneCanJoin.toString()}
              choicesMap={anyoneCanJoinChoices}
              setChoice={(choice) =>
                updateAnyoneCanJoin(choice.toString() === 'true')
              }
              toggleClassName={'h-10'}
              className={'ml-2'}
            />
          ) : (
            <span className={'text-gray-700'}>
              {anyoneCanJoin ? 'Open to all' : 'Closed (by invite only)'}
            </span>
          )}
        </Row>

        {anyoneCanJoin && user && (
          <Col className="my-4 px-2">
            <div className="text-lg">Invite</div>
            <div className={'mb-2 text-gray-500'}>
              Invite a friend to this group and get M${REFERRAL_AMOUNT} if they
              sign up!
            </div>

            <CopyLinkButton
              url={shareUrl}
              tracking="copy group share link"
              buttonClassName="btn-md rounded-l-none"
              toastClassName={'-left-28 mt-1'}
            />
          </Col>
        )}
      </Col>
    </>
  )
}

function CrossIcon(props: { onClick: () => void }) {
  const { onClick } = props

  return (
    <div>
      <button className=" text-gray-500 hover:text-gray-700" onClick={onClick}>
        <div className="absolute top-0 left-0 right-0 bottom-0 bg-gray-200 bg-opacity-50">
          <XCircleIcon className="h-12 w-12 text-gray-600" />
        </div>
      </button>
    </div>
  )
}