<template>
  <sidebar-layout>
    <template #content>
      <div class="not-found" v-if="!profile && !isLoading">
        Profile not found
      </div>
      <div
        class="profile-block"
        v-if="profile"
        :data-profile-id="profile.id"
      >
        <div class="profile-header">
          <img v-if="profile.header" :src="profile.header">
        </div>
        <div class="profile-info-group">
          <div class="avatar-menu-group">
            <div class="avatar-group">
              <avatar :profile="profile"></avatar>
              <div class="badges">
                <div
                  class="badge"
                  v-if="aliases.length > 0"
                  :title="aliases.map(profile => '@' + profile.acct).join(', ')"
                >
                  Alias
                </div>
                <div class="badge" v-if="isFollowedBy()">Follows you</div>
                <div class="badge" v-if="isSubscriptionValid()">Subscription</div>
                <div class="badge" v-if="isSubscriber()">Subscriber</div>
                <div class="badge" v-if="isMuted()">Muted</div>
              </div>
            </div>
            <div
              class="dropdown-menu-wrapper"
              v-click-away="hideProfileMenu"
            >
              <button title="More" @click="toggleProfileMenu()">
                <img src="@/assets/feather/more-vertical.svg">
              </button>
              <menu v-if="profileMenuVisible" class="dropdown-menu">
                <li v-if="!isLocalUser()">
                  <a
                    title="Open profile page"
                    :href="profile.url"
                    target="_blank"
                    rel="noreferrer"
                    @click="hideProfileMenu()"
                  >
                    Open profile page
                  </a>
                </li>
                <li v-if="isLocalUser()">
                  <a
                    :href="feedUrl"
                    target="_blank"
                  >
                    Atom feed
                  </a>
                </li>
                <li v-if="canVerifyEthereumAddress()">
                  <button
                    title="Link ethereum address"
                    @click="hideProfileMenu(); onVerifyEthereumAddress()"
                  >
                    Link ethereum address
                  </button>
                </li>
                <li v-if="isCurrentUser()">
                  <router-link
                    title="Link minisign key"
                    :to="{ name: 'identity-proof' }"
                  >
                    Link minisign key
                  </router-link>
                </li>
                <li v-if="canVerifyEthereumAddress()">
                  <button
                    title="Send signed update"
                    @click="hideProfileMenu(); onSignActivity()"
                  >
                    Send signed update
                  </button>
                </li>
                <li v-if="canManageSubscriptions()">
                  <router-link
                    title="Manage subscriptions"
                    :to="{ name: 'subscriptions-settings' }"
                  >
                    Manage subscriptions
                  </router-link>
                </li>
                <li v-if="canHideReposts()">
                  <button @click="onFollow(false, undefined)">Hide reposts</button>
                </li>
                <li v-if="canShowReposts()">
                  <button @click="onFollow(true, undefined)">Show reposts</button>
                </li>
                <li v-if="canHideReplies()">
                  <button @click="onFollow(undefined, false)">Hide replies</button>
                </li>
                <li v-if="canShowReplies()">
                  <button @click="onFollow(undefined, true)">Show replies</button>
                </li>
                <li v-if="!isMuted()">
                  <button @click="onMute()">Mute</button>
                </li>
                <li v-if="isMuted()">
                  <button @click="onUnmute()">Unmute</button>
                </li>
                <li v-if="isAdmin()">
                  <button
                    title="Copy profile ID"
                    @click="hideProfileMenu(); copyProfileId()"
                  >
                    Copy profile ID
                  </button>
                </li>
              </menu>
            </div>
          </div>
          <div class="name-buttons-group">
            <div class="name-group">
              <profile-display-name :profile="profile">
              </profile-display-name>
              <div class="actor-address">@{{ actorAddress }}</div>
            </div>
            <div class="buttons">
              <router-link
                v-if="isCurrentUser()"
                class="edit-profile btn"
                :to="{ name: 'settings-profile' }"
              >
                Edit profile
              </router-link>
              <button v-if="canFollow()" class="follow btn" @click="onFollow()">
                <span>Follow</span>
                <img
                  v-if="profile.locked"
                  title="Manually approves followers"
                  src="@/assets/forkawesome/lock.svg"
                >
              </button>
              <button v-if="canUnfollow()" class="unfollow btn" @click="onUnfollow()">
                <template v-if="isFollowRequestPending()">Cancel follow request</template>
                <template v-else>Unfollow</template>
              </button>
              <template v-if="canSubscribe()">
                <a
                  v-if="typeof profile.getSubscriptionPageLocation() === 'string'"
                  class="btn"
                  title="Pay for subscription"
                  :href="profile.getSubscriptionPageLocation() as string"
                  target="_blank"
                  rel="noreferrer"
                >
                  Subscribe
                </a>
                <router-link
                  v-else-if="profile.getSubscriptionPageLocation() !== null"
                  class="btn"
                  title="Pay for subscription"
                  :to="profile.getSubscriptionPageLocation()"
                >
                  Subscribe
                </router-link>
              </template>
            </div>
          </div>
          <div class="bio" v-html="profile.note"></div>
          <div class="extra-fields" v-if="fields.length > 0">
            <div
              v-for="field in fields"
              class="field"
              :class="{ verified: field.verified_at }"
              :key="field.name"
            >
              <div class="name" :title="field.name">{{ field.name }}</div>
              <div class="value" v-html="field.value"></div>
              <div class="verified-icon" v-if="field.verified_at">
                <img
                  src="@/assets/forkawesome/check.svg"
                  title="Verified"
                >
              </div>
            </div>
          </div>
          <div v-if="isLocalUser()" class="stats">
            <component
              class="stats-item"
              :is="isCurrentUser() ? 'a' : 'span'"
              @click="isCurrentUser() && switchTab('posts')"
            >
              <span class="value">{{ profile.statuses_count }}</span>
              <span class="label">posts</span>
            </component>
            <component
              class="stats-item"
              :is="isCurrentUser() ? 'a' : 'span'"
              @click="isCurrentUser() && switchTab('followers')"
            >
              <span class="value">{{ profile.followers_count }}</span>
              <span class="label">followers</span>
            </component>
            <component
              class="stats-item"
              :is="isCurrentUser() ? 'a' : 'span'"
              @click="isCurrentUser() && switchTab('following')"
            >
              <span class="value">{{ profile.following_count }}</span>
              <span class="label">following</span>
            </component>
            <component
              class="stats-item"
              v-if="isSubscriptionsFeatureEnabled()"
              :is="isCurrentUser() ? 'a' : 'span'"
              @click="isCurrentUser() && switchTab('subscribers')"
            >
              <span class="value">{{ profile.subscribers_count }}</span>
              <span class="label">subscribers</span>
            </component>
          </div>
        </div>
      </div>
      <div class="tab-bar" v-if="profile">
        <template v-if="tabName === 'posts' || tabName === 'posts-with-replies'">
          <a
            :class="{ active: tabName === 'posts' }"
            @click="switchTab('posts')"
          >
            Posts
          </a>
          <a
            :class="{ active: tabName === 'posts-with-replies' }"
            @click="switchTab('posts-with-replies')"
          >
            Posts and replies
          </a>
        </template>
        <span v-else-if="tabName === 'followers'" class="active">Followers</span>
        <span v-else-if="tabName === 'following'" class="active">Following</span>
        <span v-else-if="tabName === 'subscribers'" class="active">Subscribers</span>
      </div>
      <loader v-if="isLoading"></loader>
      <div :style="{ visibility: isLoading ? 'hidden' : 'visible' }">
        <post-list
          v-if="tabName === 'posts' || tabName === 'posts-with-replies'"
          :posts="posts"
          @load-next-page="loadNextPage"
        ></post-list>
        <template v-else-if="tabName === 'followers' || tabName === 'following' || tabName === 'subscribers'">
          <router-link
            v-for="profile in followList"
            :key="profile.id"
            :to="{ name: 'profile-by-acct', params: { acct: profile.acct } }"
          >
            <profile-list-item :profile="profile"></profile-list-item>
          </router-link>
          <button
            v-if="followListNextPageUrl"
            class="btn secondary next-btn"
            @click="loadFollowListNextPage()"
          >
            Show more profiles
          </button>
        </template>
      </div>
    </template>
  </sidebar-layout>
</template>

<script setup lang="ts">
import { onMounted } from "vue"
import { $, $ref, $computed } from "vue/macros"
import { useRoute } from "vue-router"

import { Post, getProfileTimeline } from "@/api/posts"
import {
  follow,
  unfollow,
  Relationship,
  getRelationship,
  getFollowers,
  getFollowing,
  mute,
  unmute,
} from "@/api/relationships"
import { getReceivedSubscriptions } from "@/api/subscriptions-common"
import {
  getAliases,
  getProfile,
  lookupProfile,
  Permissions,
  Profile,
  ProfileField,
  ProfileWrapper,
  EXTRA_FIELD_COUNT_MAX,
} from "@/api/users"
import Avatar from "@/components/Avatar.vue"
import Loader from "@/components/Loader.vue"
import PostList from "@/components/PostList.vue"
import ProfileDisplayName from "@/components/ProfileDisplayName.vue"
import ProfileListItem from "@/components/ProfileListItem.vue"
import SidebarLayout from "@/components/SidebarLayout.vue"
import { useEthereumAddressVerification } from "@/composables/ethereum-address-verification"
import { useInstanceInfo } from "@/composables/instance"
import { useSignedActivity } from "@/composables/signed-activity"
import { useCurrentUser } from "@/composables/user"
import { BACKEND_URL } from "@/constants"
import { hasEthereumWallet } from "@/utils/ethereum"

const route = useRoute()
const {
  authToken,
  currentUser,
  ensureAuthToken,
} = $(useCurrentUser())
const { verifyEthereumAddress } = useEthereumAddressVerification()
const { getActorAddress, getBlockchainInfo } = $(useInstanceInfo())

let profile = $ref<ProfileWrapper | null>(null)
let relationship = $ref<Relationship | null>(null)
let aliases = $ref<Profile[]>([])

let profileMenuVisible = $ref(false)

let tabName = $ref("posts")
let isLoading = $ref(false)
let posts = $ref<Post[]>([])
let followList = $ref<Profile[]>([])
let followListNextPageUrl = $ref<string | null>(null)

onMounted(async () => {
  isLoading = true
  try {
    let _profile
    if (route.params.acct) {
      _profile = await lookupProfile(
        authToken,
        route.params.acct as string,
      )
    } else {
      _profile = await getProfile(
        authToken,
        route.params.profileId as string,
      )
    }
    profile = new ProfileWrapper(_profile)
  } catch (error: any) {
    if (error.message === "profile not found") {
      // Show "not found" text
      isLoading = false
      return
    }
    throw error
  }
  if (currentUser && !isCurrentUser()) {
    relationship = await getRelationship(
      ensureAuthToken(),
      profile.id,
    )
  }
  if (profile.identity_proofs.length > 0) {
    const { verified } = await getAliases(profile.id)
    aliases = verified
  }
  await switchTab("posts")
  isLoading = false
})

async function switchTab(name: string) {
  if (!profile) {
    return
  }
  isLoading = true
  tabName = name
  if (tabName === "posts") {
    posts = await getProfileTimeline(
      authToken,
      profile.id,
      true,
    )
  } else if (tabName === "posts-with-replies") {
    posts = await getProfileTimeline(
      authToken,
      profile.id,
      false,
    )
  } else if (tabName === "followers" && isCurrentUser()) {
    const page = await getFollowers(
      ensureAuthToken(),
      profile.id,
    )
    followList = page.profiles
    followListNextPageUrl = page.nextPageUrl
  } else if (tabName === "following" && isCurrentUser()) {
    const page = await getFollowing(
      ensureAuthToken(),
      profile.id,
    )
    followList = page.profiles
    followListNextPageUrl = page.nextPageUrl
  } else if (tabName === "subscribers" && isCurrentUser()) {
    const subscriptions = await getReceivedSubscriptions(
      ensureAuthToken(),
      profile.id,
    )
    followList = subscriptions.map((subscription) => subscription.sender)
    followListNextPageUrl = null
  }
  isLoading = false
}

const actorAddress = $computed<string>(() => {
  if (!profile) {
    return ""
  }
  return getActorAddress(profile)
})

const fields = $computed<ProfileField[]>(() => {
  if (!profile) {
    return []
  }
  return profile.identity_proofs
    .concat(profile.fields)
    .slice(0, EXTRA_FIELD_COUNT_MAX)
})

function isCurrentUser(): boolean {
  if (!currentUser || !profile) {
    return false
  }
  return currentUser.id === profile.id
}

function isFollowedBy(): boolean {
  if (!relationship) {
    return false
  }
  return relationship.followed_by
}

function isSubscriptionValid(): boolean {
  if (!relationship) {
    return false
  }
  return relationship.subscription_to
}

function isSubscriber(): boolean {
  if (!relationship) {
    return false
  }
  return relationship.subscription_from
}

function isMuted(): boolean {
  if (!relationship) {
    return false
  }
  return relationship.muting
}

function canFollow(): boolean {
  if (!relationship) {
    return false
  }
  return !relationship.following && !relationship.requested
}

function canUnfollow(): boolean {
  if (!relationship) {
    return false
  }
  return (relationship.following || relationship.requested)
}

function isFollowRequestPending(): boolean {
  if (!relationship) {
    return false
  }
  return relationship.requested
}

function canHideReposts(): boolean {
  if (!relationship) {
    return false
  }
  return (relationship.following || relationship.requested) && relationship.showing_reblogs
}

function canShowReposts(): boolean {
  if (!relationship) {
    return false
  }
  return (relationship.following || relationship.requested) && !relationship.showing_reblogs
}

function canHideReplies(): boolean {
  if (!relationship) {
    return false
  }
  return (relationship.following || relationship.requested) && relationship.showing_replies
}

function canShowReplies(): boolean {
  if (!relationship) {
    return false
  }
  return (relationship.following || relationship.requested) && !relationship.showing_replies
}

async function onFollow(showReposts?: boolean, showReplies?: boolean) {
  if (!currentUser || !profile || !relationship) {
    return
  }
  relationship = await follow(
    ensureAuthToken(),
    profile.id,
    showReposts ?? relationship.showing_reblogs,
    showReplies ?? relationship.showing_replies,
  )
}

async function onMute() {
  if (!currentUser || !profile) {
    return
  }
  relationship = await mute(
    ensureAuthToken(),
    profile.id,
  )
}

async function onUnmute() {
  if (!currentUser || !profile) {
    return
  }
  relationship = await unmute(
    ensureAuthToken(),
    profile.id,
  )
}

async function onUnfollow() {
  if (!currentUser || !profile) {
    return
  }
  relationship = await unfollow(
    ensureAuthToken(),
    profile.id,
  )
}

function toggleProfileMenu() {
  profileMenuVisible = !profileMenuVisible
}

function hideProfileMenu() {
  profileMenuVisible = false
}

function isLocalUser(): boolean {
  if (!profile) {
    return false
  }
  return profile.username === profile.acct
}

const feedUrl = $computed<string>(() => {
  if (!profile || !isLocalUser()) {
    return ""
  }
  return `${BACKEND_URL}/feeds/users/${profile.username}`
})

function canVerifyEthereumAddress(): boolean {
  return isCurrentUser() && hasEthereumWallet()
}

async function onVerifyEthereumAddress() {
  if (!profile || !isCurrentUser()) {
    return
  }
  const user = await verifyEthereumAddress()
  if (user) {
    profile.identity_proofs = user.identity_proofs
  }
}

async function onSignActivity() {
  if (!profile || !isCurrentUser()) {
    return
  }
  const { signUpdateActivity } = useSignedActivity()
  await signUpdateActivity()
}

function isSubscriptionsFeatureEnabled(): boolean {
  const blockchain = getBlockchainInfo()
  return Boolean(blockchain?.features.subscriptions)
}

function canManageSubscriptions(): boolean {
  return (
    isSubscriptionsFeatureEnabled() &&
    profile !== null &&
    currentUser !== null &&
    isCurrentUser() &&
    currentUser.role.permissions.includes(Permissions.ManageSubscriptionOptions)
  )
}

function canSubscribe(): boolean {
  return (
    isSubscriptionsFeatureEnabled() &&
    profile !== null &&
    profile.getSubscriptionPageLocation() !== null &&
    !isCurrentUser()
  )
}

function isAdmin(): boolean {
  if (!currentUser) {
    return false
  }
  return currentUser.role.permissions.includes(Permissions.DeleteAnyProfile)
}

function copyProfileId(): void {
  if (!profile) {
    return
  }
  navigator.clipboard.writeText(profile.id)
}

async function loadNextPage(maxId: string) {
  if (!profile) {
    return
  }
  const nextPage = await getProfileTimeline(
    authToken,
    profile.id,
    tabName !== "posts-with-replies",
    maxId,
  )
  posts = [...posts, ...nextPage]
}

async function loadFollowListNextPage() {
  if (!profile || !followListNextPageUrl) {
    return
  }
  let loadFollowList
  if (tabName === "followers") {
    loadFollowList = getFollowers
  } else if (tabName === "following") {
    loadFollowList = getFollowing
  } else {
    throw new Error("wrong tab")
  }
  const page = await loadFollowList(
    ensureAuthToken(),
    profile.id,
    followListNextPageUrl,
  )
  followList.push(...page.profiles)
  followListNextPageUrl = page.nextPageUrl
}
</script>

<style scoped lang="scss">
@import "../styles/layout";
@import "../styles/mixins";
@import "../styles/theme";

$avatar-size: 185px;

.profile-block {
  @include block-btn;

  background-color: var(--block-background-color);
  border-radius: $block-border-radius;
  margin-bottom: $block-outer-padding;

  .profile-header {
    background-color: var(--btn-background-color);
    border-radius: $block-border-radius $block-border-radius 0 0;
    height: 200px;

    img {
      border-radius: inherit;
      height: 100%;
      object-fit: cover;
      width: 100%;
    }
  }
}

.profile-info-group {
  display: flex;
  flex-direction: column;
  gap: $block-inner-padding;
  padding: $block-inner-padding;
}

.avatar-menu-group {
  display: flex;
  flex-direction: row;
  gap: $block-inner-padding;

  .avatar-group {
    align-items: flex-start;
    display: flex;
    flex-direction: row;
    flex-grow: 1;
    flex-wrap: wrap;
    gap: calc($block-inner-padding / 2) $block-inner-padding;
  }

  .avatar {
    height: $avatar-size * 1.5;
    margin-right: auto;
    margin-top: calc(-1 * ($avatar-size / 2 + $block-inner-padding));
    min-width: $avatar-size;
    padding: 7px;
    width: $avatar-size;
  }

  .badges {
    display: flex;
    flex-wrap: wrap;
    gap: calc($block-inner-padding / 2) $block-inner-padding;
  }

  .badge {
    border: 1px solid var(--btn-background-color);
    border-radius: $btn-border-radius;
    font-size: 14px;
    line-height: 30px;
    padding: 0 7px;
    white-space: nowrap;
  }

  .dropdown-menu-wrapper {
    @include block-dropdown-menu;

    /* stylelint-disable-next-line selector-max-compound-selectors */
    button img {
      filter: var(--link-colorizer);
      height: 32px;
      min-width: 20px;
      object-fit: none;
      width: 20px;

      /* stylelint-disable-next-line selector-max-compound-selectors */
      &:hover {
        filter: var(--link-hover-colorizer);
      }
    }

    .dropdown-menu {
      right: 0;
    }
  }
}

.name-buttons-group {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: $block-inner-padding;

  .name-group {
    flex-grow: 1;
    font-size: 16px;
    line-height: 1.3;
    overflow-x: hidden;

    .display-name {
      font-weight: bold;
    }

    .actor-address {
      color: var(--secondary-text-color);
      overflow-x: hidden;
      text-overflow: ellipsis;
      user-select: all;
    }
  }

  .buttons {
    display: flex;
    gap: $block-inner-padding;
  }
}

.follow {
  align-items: center;
  display: flex;
  gap: $input-padding;

  img {
    $icon-size: 1em;

    filter: var(--btn-text-colorizer);
    height: $icon-size;
    min-width: $icon-size;
    width: $icon-size;
  }

  &:hover {
    img {
      filter: var(--text-colorizer);
    }
  }
}

.bio {
  white-space: pre-line;
  word-wrap: break-word;

  :deep(a) {
    @include block-link;
  }
}

.extra-fields {
  border-bottom: 1px solid var(--separator-color);

  .field {
    border-top: 1px solid var(--separator-color);
    display: flex;
    gap: calc($block-inner-padding / 2);
    padding: calc($block-inner-padding / 2) 0;

    .name {
      font-weight: bold;
      min-width: 120px;
      overflow-x: hidden;
      text-overflow: ellipsis;
      width: 120px;
    }

    .value {
      flex-grow: 1;
      overflow-x: hidden;
      text-overflow: ellipsis;
    }

    &.verified .value {
      font-weight: bold;
    }

    /* stylelint-disable-next-line selector-max-compound-selectors */
    .verified-icon img {
      filter: var(--text-colorizer);
      height: 1em;
      min-width: 1em;
      width: 1em;
    }
  }

  &:last-child {
    border-bottom: none;
  }
}

.stats {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  font-weight: bold;
  gap: $block-inner-padding 30px;
  text-align: center;

  .stats-item {
    display: flex;
    gap: 5px;

    .value {
      font-size: 18px;
    }

    .label {
      align-self: flex-end;
      color: var(--secondary-text-color);
    }
  }
}

.tab-bar {
  align-items: center;
  display: flex;
  margin-bottom: $block-outer-padding;

  a,
  span {
    border-radius: $block-border-radius;
    padding: calc($block-inner-padding / 2);
    text-align: center;
    width: 100%;

    &.active {
      background-color: var(--block-background-color);
      font-weight: bold;
    }
  }
}

/* profile-list-item */
.profile {
  margin-bottom: $block-outer-padding;
}

.loader {
  margin: 0 auto;
}

.not-found {
  font-size: 20px;
  text-align: center;
}
</style>
