import {
  CrumbSchema,
  FeedItemSchema,
  ProfileDetailSchema,
  PublicProfileSchema,
  TrailSchema,
  type Crumb,
  type FeedItem,
  type ProfileDetail,
  type PublicProfile,
  type Trail,
} from '@crumbs/core/schemas'

import {
  crumbDropped,
  crumbSynced,
  trailDropped,
  trailPatched,
} from '@/lib/entity-sync'
import {unwrap} from '@/lib/errors'
import {
  matchesFeedCrumb,
  matchesFeedTrail,
  withPatchedTrail,
  withSyncedCrumb,
} from '@/lib/feed-items'
import {createKeyedPagedStore} from '@/lib/keyed-paged-resource'
import {
  createKeyedDetailStore,
  keyedDetailHooks,
} from '@/lib/keyed-resource'
import {pageParams} from '@/lib/paged-resource'
import {rpc} from '@/lib/rpc'
import {fromSchema} from '@/lib/snapshot-cache'
import {
  keyedDetailSnapshot,
  keyedPagedSnapshot,
} from '@/lib/snapshots'

export type {ProfileDetail}

// profile header (counts + previews + friendship state)
const useProfileStore = createKeyedDetailStore(
  async (id: string) => {
    const {profile} = await unwrap(
      rpc.users[':id'].$get({param: {id}}),
    )
    return profile
  },
  keyedDetailSnapshot(
    'profile-detail',
    1,
    fromSchema(ProfileDetailSchema),
  ),
)

// a profile's crumbs + trails tabs: paged, keyed by user id
export const profileCrumbs = createKeyedPagedStore<Crumb>(
  (id) => async (cursor) => {
    const {crumbs, nextCursor} = await unwrap(
      rpc.users[':id'].crumbs.$get({
        param: {id},
        query: pageParams(cursor),
      }),
    )
    return {items: crumbs, nextCursor}
  },
  keyedPagedSnapshot('profile-crumbs', 1, fromSchema(CrumbSchema)),
)

export const profileTrails = createKeyedPagedStore<Trail>(
  (id) => async (cursor) => {
    const {trails, nextCursor} = await unwrap(
      rpc.users[':id'].trails.$get({
        param: {id},
        query: pageParams(cursor),
      }),
    )
    return {items: trails, nextCursor}
  },
  keyedPagedSnapshot('profile-trails', 1, fromSchema(TrailSchema)),
)

// a profile's friends: paged, keyed by user id
export const profileFriends = createKeyedPagedStore<PublicProfile>(
  (id) => async (cursor) => {
    const {friends, nextCursor} = await unwrap(
      rpc.users[':id'].friends.$get({
        param: {id},
        query: pageParams(cursor),
      }),
    )
    return {items: friends, nextCursor}
  },
  keyedPagedSnapshot(
    'profile-friends',
    1,
    fromSchema(PublicProfileSchema),
  ),
)

// a profile's interleaved recent activity: paged, keyed by user id
export const profileActivity = createKeyedPagedStore<FeedItem>(
  (id) => async (cursor) => {
    const {items, nextCursor} = await unwrap(
      rpc.users[':id'].activity.$get({
        param: {id},
        query: pageParams(cursor),
      }),
    )
    return {items, nextCursor}
  },
  keyedPagedSnapshot(
    'profile-activity',
    1,
    fromSchema(FeedItemSchema),
  ),
)

crumbSynced.subscribe((crumb) => {
  profileCrumbs.mapItems((c) => (c.id === crumb.id ? crumb : c))
  profileActivity.mapItems(withSyncedCrumb(crumb))
})
crumbDropped.subscribe((id) => {
  profileCrumbs.removeItem((c) => c.id === id)
  profileActivity.removeItem(matchesFeedCrumb(id))
})
trailPatched.subscribe(({id, patch}) => {
  profileTrails.mapItems((t) => (t.id === id ? patch(t) : t))
  profileActivity.mapItems(withPatchedTrail(id, patch))
})
trailDropped.subscribe((id) => {
  profileTrails.removeItem((t) => t.id === id)
  profileActivity.removeItem(matchesFeedTrail(id))
})

export const {
  useData: useProfile,
  useLoading: useProfileLoading,
  useError: useProfileError,
} = keyedDetailHooks(useProfileStore)
export const useLoadProfile = () => useProfileStore((s) => s.load)

// the detail-screen face of a profile (for @/hooks/use-detail)
export const profileDetail = {
  useData: useProfile,
  useLoading: useProfileLoading,
  useError: useProfileError,
  useLoad: useLoadProfile,
}
