(define-trait nft-trait
  (
    (get-last-token-id () (response uint uint))

    (get-token-uri (uint) (response (optional (string-ascii 256)) uint))

    (get-owner (uint) (response (optional principal) uint))

    (transfer (uint principal principal) (response bool uint))))
  


(define-map hais {hai-id: uint}
  {name: (string-ascii 20),target-aip: (string-ascii 20),num-timeblocks: uint, date-of-birth: uint})
  
  
  


(define-read-only (get-meta-data (hai-id uint))
  (map-get? hais {hai-id: hai-id}))

(define-non-fungible-token nft-hais uint)
(define-data-var next-id uint u1)

(define-private (get-time)
   (unwrap-panic (get-block-info? time (- block-height u1))))

(define-public (create-hai (name (string-ascii 20)) (target-aip (string-ascii 20)) (num-timeblocks uint))
  (let ((hai-id (var-get next-id)))
    (if (is-ok (nft-mint? nft-hais hai-id tx-sender))
      (begin
        (var-set next-id (+ hai-id u1))
        (map-set hais {hai-id: hai-id}{name: name, target-aip: 
                                       target-aip, num-timeblocks: num-timeblocks, date-of-birth: (get-time)})
      
        
        (ok hai-id))
      err-hai-exists)))

(define-public (transfer (hai-id uint) (sender principal) (recipient principal))
  (let ((owner (unwrap! (unwrap-panic (get-owner hai-id)) err-hai-unborn)))
    (if (is-eq owner sender)
      (match (nft-transfer? nft-hais hai-id sender recipient)
        success (ok success)
        error (err-nft-transfer error))
      err-transfer-not-allowed)))

(define-read-only (get-last-token-id)
  (ok (- (var-get next-id) u1)))


(define-read-only (get-token-uri (hai-id uint))
  (ok none))

(define-read-only (get-owner (hai-id uint))
  (match (nft-get-owner? nft-hais hai-id)
    owner (ok (some owner))
    (ok none)))
  
(define-constant err-transfer-not-allowed (err u401)) 
(define-constant err-hai-unborn (err u404)) 
(define-constant err-sender-equals-recipient (err u405)) 
(define-constant err-hai-exists (err u409)) 
(define-constant err-hai-died (err u501)) 


(define-map err-strings (response uint uint) (string-ascii 32))
(map-insert err-strings err-transfer-not-allowed "transfer-not-allowed")
(map-insert err-strings err-hai-unborn "hai-unborn")
(map-insert err-strings err-sender-equals-recipient "sender-equals-recipient")
(map-insert err-strings err-hai-exists "hai-exists")
(map-insert err-strings err-hai-died "hai-died")

(define-private (err-nft-transfer (code uint))
  (if (is-eq u1 code)
    err-transfer-not-allowed
    (if (is-eq u2 code)
      err-sender-equals-recipient
      (if (is-eq u3 code)
        err-hai-unborn
        (err code)))))

(define-private (err-nft-mint (code uint))
  (if (is-eq u1 code)
    err-hai-exists
    (err code)))

(define-read-only (get-errstr (code uint))
  (unwrap! (map-get? err-strings (err code)) "unknown-error"))