import { type FormEvent, useEffect, useState } from 'react'
import { Link, useParams } from 'react-router-dom'
import { ApiHttpError } from '../../api/http'
import {
  fetchPermissionsList,
  fetchRolePermissionMatrix,
  fetchRolesList,
  saveRolePermissionMatrix,
  type PermissionMatrixRow,
} from '../../api/rolePermission'
import { ROLE_PERMISSION_BASE } from './rolePermissionPaths'

type Flags = { create: boolean; read: boolean; update: boolean; delete: boolean }

function draftStorageKey(roleId: string): string {
  return `role-permission-draft:${roleId}`
}

function permissionKey(
  permission: PermissionMatrixRow,
  index: number,
): string {
  const rawId = String(permission.permission_id ?? permission.id ?? '').trim()
  if (rawId !== '' && rawId !== '0') {
    return rawId
  }

  const name = String(permission.name ?? '').trim().toLowerCase()
  if (name !== '') {
    return `name:${name}:${index}`
  }

  return `permission:${index}`
}

export function EditRolePermissionsPage() {
  const { roleId: routeRoleId } = useParams<{ roleId: string }>()
  const [roles, setRoles] = useState<Array<{ id?: number | string; name?: string }>>([])
  const [selectedRoleId, setSelectedRoleId] = useState(routeRoleId ?? '')
  const [permissions, setPermissions] = useState<PermissionMatrixRow[]>([])
  const [matrix, setMatrix] = useState<Record<string, Flags>>({})
  const [matrixRoleId, setMatrixRoleId] = useState('')
  const [loading, setLoading] = useState(false)
  const [msg, setMsg] = useState<string | null>(null)

  useEffect(() => {
    fetchRolesList()
      .then((d) => setRoles(d.roles ?? []))
      .catch(() => {})
  }, [])

  useEffect(() => {
    if (routeRoleId) setSelectedRoleId(routeRoleId)
  }, [routeRoleId])

  function loadMatrix(rid: string) {
    if (!rid) {
      setPermissions([])
      setMatrix({})
      setMatrixRoleId('')
      return
    }
    setLoading(true)
    setMsg(null)
    setPermissions([])
    setMatrix({})
    setMatrixRoleId('')
    Promise.all([fetchPermissionsList(), fetchRolePermissionMatrix(rid)])
      .then(([allPermissions, roleMatrix]) => {
        const permissionRows: PermissionMatrixRow[] = (allPermissions.permissions ?? []).map((p) => ({
          id: p.id,
          permission_id: p.id,
          name: p.name,
          description: p.description,
        }))
        setPermissions(permissionRows)

        const ex = roleMatrix.existing ?? {}
        const flagsByPermissionId = new Map<string, PermissionMatrixRow>()
        for (const row of roleMatrix.permissions ?? []) {
          const rawId = String(row.permission_id ?? row.id ?? '').trim()
          if (rawId !== '') {
            flagsByPermissionId.set(rawId, row)
          }
        }

        const next: Record<string, Flags> = {}
        for (const [index, p] of permissionRows.entries()) {
          const pid = permissionKey(p, index)
          const direct = flagsByPermissionId.get(String(p.permission_id ?? p.id ?? '').trim())
          const e =
            direct ??
            ex[pid] ??
            ex[p.permission_id as keyof typeof ex] ??
            ex[p.id as keyof typeof ex]
          next[pid] = {
            create: Boolean(e?.can_create),
            read: Boolean(e?.can_read),
            update: Boolean(e?.can_update),
            delete: Boolean(e?.can_delete),
          }
        }
        try {
          const rawDraft = sessionStorage.getItem(draftStorageKey(rid))
          if (rawDraft) {
            const parsed = JSON.parse(rawDraft) as Record<string, Partial<Flags>>
            for (const [key, value] of Object.entries(parsed)) {
              next[key] = {
                create: Boolean(value?.create),
                read: Boolean(value?.read),
                update: Boolean(value?.update),
                delete: Boolean(value?.delete),
              }
            }
          }
        } catch {
          // Ignore malformed local drafts and prefer server state.
        }
        setMatrix(next)
        setMatrixRoleId(rid)
      })
      .catch(() => setMsg('Failed to load permissions matrix.'))
      .finally(() => setLoading(false))
  }

  useEffect(() => {
    loadMatrix(selectedRoleId)
  }, [selectedRoleId])

  useEffect(() => {
    if (!selectedRoleId || matrixRoleId !== selectedRoleId) return
    try {
      sessionStorage.setItem(draftStorageKey(selectedRoleId), JSON.stringify(matrix))
    } catch {
      // Ignore storage write failures.
    }
  }, [matrix, matrixRoleId, selectedRoleId])

  function setFlag(pid: string, key: keyof Flags, val: boolean) {
    setMatrix((m) => ({
      ...m,
      [pid]: { ...defaultFlags(m[pid]), [key]: val },
    }))
  }

  function selectAll() {
    setMatrix((m) => {
      const next = { ...m }
      for (const [index, p] of permissions.entries()) {
        const pid = permissionKey(p, index)
        next[pid] = { create: true, read: true, update: true, delete: true }
      }
      return next
    })
  }

  function deselectAll() {
    setMatrix((m) => {
      const next = { ...m }
      for (const [index, p] of permissions.entries()) {
        const pid = permissionKey(p, index)
        next[pid] = { create: false, read: false, update: false, delete: false }
      }
      return next
    })
  }

  async function onSubmit(e: FormEvent) {
    e.preventDefault()
    if (!selectedRoleId) return
    setMsg(null)
    const payload: Record<string, { create?: boolean; read?: boolean; update?: boolean; delete?: boolean }> =
      {}
    for (const [index, p] of permissions.entries()) {
      const pid = permissionKey(p, index)
      const f = matrix[pid] ?? { create: false, read: false, update: false, delete: false }
      payload[pid] = {
        create: f.create,
        read: f.read,
        update: f.update,
        delete: f.delete,
      }
    }
    try {
      await saveRolePermissionMatrix(selectedRoleId, payload)
      sessionStorage.removeItem(draftStorageKey(selectedRoleId))
      setMsg('Saved.')
    } catch (err: unknown) {
      setMsg(err instanceof ApiHttpError ? err.message : 'Save failed.')
    }
  }

  return (
    <div className="container-fluid py-3">
      <h2 className="text-center mt-4 mb-3">Edit Role Permissions</h2>

      {msg ? <div className="alert alert-info">{msg}</div> : null}

      <div className="d-flex justify-content-center flex-wrap gap-2 mb-3">
        <button type="button" className="btn btn-secondary" onClick={selectAll}>
          Select All
        </button>
        <button type="button" className="btn btn-secondary" onClick={deselectAll}>
          Deselect All
        </button>
        <button form="permissionsForm" type="submit" className="btn btn-primary">
          Save Permissions
        </button>
        <Link to={`${ROLE_PERMISSION_BASE}/roles`} className="btn btn-outline-secondary">
          Cancel
        </Link>
      </div>

      <form id="roleSelectForm" className="mb-3" onSubmit={(e) => e.preventDefault()}>
        <div className="form-group" style={{ maxWidth: 480 }}>
          <label className="form-label" htmlFor="roleSelect">
            Select Role
          </label>
          <select
            id="roleSelect"
            className="form-control"
            value={selectedRoleId}
            onChange={(e) => setSelectedRoleId(e.target.value)}
          >
            <option value="">-- Select Role --</option>
            {roles.map((r) => (
              <option key={String(r.id)} value={String(r.id)}>
                {String(r.name ?? r.id)}
              </option>
            ))}
          </select>
        </div>
      </form>

      <form id="permissionsForm" onSubmit={onSubmit} style={{ display: selectedRoleId ? '' : 'none' }}>
        <input type="hidden" name="role_id" value={selectedRoleId} />
        <div className="table-responsive">
          <table className="table table-bordered table-striped align-middle w-100">
            <thead className="table-light">
              <tr>
                <th style={{ minWidth: 260 }}>Permission</th>
                <th>Create</th>
                <th>Read</th>
                <th>Update</th>
                <th>Delete</th>
              </tr>
            </thead>
            <tbody>
              {loading ? (
                <tr>
                  <td colSpan={5} className="text-center text-muted py-4">
                    Loading…
                  </td>
                </tr>
              ) : (
                permissions.map((p, index) => {
                  const pid = permissionKey(p, index)
                  const f = matrix[pid] ?? { create: false, read: false, update: false, delete: false }
                  return (
                    <tr key={pid}>
                      <td>{String(p.name ?? '')}</td>
                      <td className="text-center">
                        <input
                          type="checkbox"
                          checked={f.create}
                          onChange={(e) => setFlag(pid, 'create', e.target.checked)}
                        />
                      </td>
                      <td className="text-center">
                        <input
                          type="checkbox"
                          checked={f.read}
                          onChange={(e) => setFlag(pid, 'read', e.target.checked)}
                        />
                      </td>
                      <td className="text-center">
                        <input
                          type="checkbox"
                          checked={f.update}
                          onChange={(e) => setFlag(pid, 'update', e.target.checked)}
                        />
                      </td>
                      <td className="text-center">
                        <input
                          type="checkbox"
                          checked={f.delete}
                          onChange={(e) => setFlag(pid, 'delete', e.target.checked)}
                        />
                      </td>
                    </tr>
                  )
                })
              )}
            </tbody>
          </table>
        </div>

        <div className="d-flex justify-content-center flex-wrap gap-2 mt-3">
          <button type="button" className="btn btn-secondary" onClick={selectAll}>
            Select All
          </button>
          <button type="button" className="btn btn-secondary" onClick={deselectAll}>
            Deselect All
          </button>
          <button type="submit" className="btn btn-primary">
            Save Permissions
          </button>
          <Link to={`${ROLE_PERMISSION_BASE}/roles`} className="btn btn-outline-secondary">
            Cancel
          </Link>
        </div>
      </form>
    </div>
  )
}

function defaultFlags(f?: Flags): Flags {
  return {
    create: f?.create ?? false,
    read: f?.read ?? false,
    update: f?.update ?? false,
    delete: f?.delete ?? false,
  }
}
