/**
 * Documents store: reference documents, their items, and item versions.
 *
 * Maps to the backend /api/v1/documents endpoints.
 */

export interface DocumentItem {
  id: string
  document_id: string
  position: string
  item_type: string
  title: string | null
  current_text: string
  voting_protocol_id: string | null
  sort_order: number
  section_tag: string | null
  inertia_preset: string
  is_permanent_vote: boolean
  created_at: string
  updated_at: string
}

export interface Document {
  id: string
  slug: string
  title: string
  doc_type: string
  version: string
  status: string
  description: string | null
  ipfs_cid: string | null
  chain_anchor: string | null
  genesis_json: string | null
  created_at: string
  updated_at: string
  items_count: number
}

export interface ItemVersion {
  id: string
  item_id: string
  version_number: number
  proposed_text: string
  rationale: string | null
  diff: string | null
  status: string
  proposed_by: string | null
  reviewed_by: string | null
  created_at: string
  updated_at: string
}

export interface DocumentCreate {
  slug: string
  title: string
  doc_type: string
  description?: string | null
  version?: string
}

export interface VersionProposal {
  proposed_text: string
  rationale?: string | null
}

interface DocumentsState {
  list: Document[]
  current: Document | null
  items: DocumentItem[]
  versions: ItemVersion[]
  allItemVersions: Record<string, ItemVersion[]>
  loadingVersions: boolean
  loading: boolean
  error: string | null
}

export const useDocumentsStore = defineStore('documents', {
  state: (): DocumentsState => ({
    list: [],
    current: null,
    items: [],
    versions: [],
    allItemVersions: {},
    loadingVersions: false,
    loading: false,
    error: null,
  }),

  getters: {
    byType: (state) => {
      return (docType: string) => state.list.filter(d => d.doc_type === docType)
    },
    activeDocuments: (state): Document[] => {
      return state.list.filter(d => d.status === 'active')
    },
    draftDocuments: (state): Document[] => {
      return state.list.filter(d => d.status === 'draft')
    },
  },

  actions: {
    /**
     * Fetch all documents with optional filters.
     */
    async fetchAll(params?: { doc_type?: string; status?: string }) {
      this.loading = true
      this.error = null

      try {
        const { $api } = useApi()
        const query: Record<string, string> = {}
        if (params?.doc_type) query.doc_type = params.doc_type
        if (params?.status) query.status = params.status

        this.list = await $api<Document[]>('/documents/', { query })
      } catch (err: any) {
        this.error = err?.data?.detail || err?.message || 'Erreur lors du chargement des documents'
      } finally {
        this.loading = false
      }
    },

    /**
     * Fetch a single document by slug and its items.
     */
    async fetchBySlug(slug: string) {
      this.loading = true
      this.error = null

      try {
        const { $api } = useApi()

        const [doc, items] = await Promise.all([
          $api<Document>(`/documents/${slug}`),
          $api<DocumentItem[]>(`/documents/${slug}/items`),
        ])

        this.current = doc
        this.items = items
      } catch (err: any) {
        this.error = err?.data?.detail || err?.message || 'Document introuvable'
      } finally {
        this.loading = false
      }
    },

    /**
     * Create a new reference document.
     */
    async createDocument(payload: DocumentCreate) {
      this.loading = true
      this.error = null

      try {
        const { $api } = useApi()
        const doc = await $api<Document>('/documents/', {
          method: 'POST',
          body: payload,
        })
        this.list.unshift(doc)
        return doc
      } catch (err: any) {
        this.error = err?.data?.detail || err?.message || 'Erreur lors de la creation du document'
        throw err
      } finally {
        this.loading = false
      }
    },

    /**
     * Fetch all versions for a specific item within a document.
     */
    async fetchItemVersions(slug: string, itemId: string) {
      this.loading = true
      this.error = null

      try {
        const { $api } = useApi()
        this.versions = await $api<ItemVersion[]>(
          `/documents/${slug}/items/${itemId}/versions`,
        )
      } catch (err: any) {
        this.error = err?.data?.detail || err?.message || 'Erreur lors du chargement des versions'
      } finally {
        this.loading = false
      }
    },

    /**
     * Propose a new version for a document item.
     */
    async proposeVersion(slug: string, itemId: string, data: VersionProposal) {
      this.error = null

      try {
        const { $api } = useApi()
        const version = await $api<ItemVersion>(
          `/documents/${slug}/items/${itemId}/versions`,
          {
            method: 'POST',
            body: data,
          },
        )
        this.versions.unshift(version)
        return version
      } catch (err: any) {
        this.error = err?.data?.detail || err?.message || 'Erreur lors de la proposition'
        throw err
      }
    },

    /**
     * Accept a proposed version.
     */
    async acceptVersion(slug: string, itemId: string, versionId: string) {
      this.error = null

      try {
        const { $api } = useApi()
        const updated = await $api<ItemVersion>(
          `/documents/${slug}/items/${itemId}/versions/${versionId}/accept`,
          { method: 'POST' },
        )
        const idx = this.versions.findIndex(v => v.id === versionId)
        if (idx >= 0) this.versions[idx] = updated
        return updated
      } catch (err: any) {
        this.error = err?.data?.detail || err?.message || 'Erreur lors de l\'acceptation'
        throw err
      }
    },

    /**
     * Reject a proposed version.
     */
    async rejectVersion(slug: string, itemId: string, versionId: string) {
      this.error = null

      try {
        const { $api } = useApi()
        const updated = await $api<ItemVersion>(
          `/documents/${slug}/items/${itemId}/versions/${versionId}/reject`,
          { method: 'POST' },
        )
        const idx = this.versions.findIndex(v => v.id === versionId)
        if (idx >= 0) this.versions[idx] = updated
        return updated
      } catch (err: any) {
        this.error = err?.data?.detail || err?.message || 'Erreur lors du rejet'
        throw err
      }
    },

    /**
     * Fetch all versions for every item in a document (parallel).
     * Used to compute the "projected" view (document as-if all active votes passed).
     */
    async fetchAllItemVersions(slug: string, itemIds: string[]) {
      this.loadingVersions = true
      try {
        const { $api } = useApi()
        const results = await Promise.allSettled(
          itemIds.map(id => $api<ItemVersion[]>(`/documents/${slug}/items/${id}/versions`)),
        )
        const map: Record<string, ItemVersion[]> = {}
        itemIds.forEach((id, i) => {
          const r = results[i]
          map[id] = r?.status === 'fulfilled' ? r.value : []
        })
        this.allItemVersions = map
      } finally {
        this.loadingVersions = false
      }
    },

    /**
     * Archive a document into the Sanctuary.
     */
    async archiveDocument(slug: string) {
      this.error = null

      try {
        const { $api } = useApi()
        const doc = await $api<Document>(
          `/documents/${slug}/archive`,
          { method: 'POST' },
        )
        // Update current if viewing this document
        if (this.current?.slug === slug) {
          this.current = doc
        }
        // Update in list
        const idx = this.list.findIndex(d => d.slug === slug)
        if (idx >= 0) this.list[idx] = doc
        return doc
      } catch (err: any) {
        this.error = err?.data?.detail || err?.message || 'Erreur lors de l\'archivage'
        throw err
      }
    },

    /**
     * Clear the current document, items and versions.
     */
    clearCurrent() {
      this.current = null
      this.items = []
      this.versions = []
      this.allItemVersions = {}
      this.loadingVersions = false
    },
  },
})
