(define-constant ERR-NOT-AUTHORIZED (err u401))
(define-constant ERR-NOT-OWNER (err u201))
(define-constant ERR-NOT-BUYER (err u301))
(define-constant ERR-NOT-ACTIVE (err u501))
(define-constant ERR-NOT-ON (err u601))
(define-constant ERR-BID-NOT-HIGH-ENOUGH (err u100))
(define-constant ERR-NOT-OPTIONAL (err u1000))
(define-constant ERR-ITEM-NOT-FOR-SALE (err u101))
(define-constant ERR-ITEM-PRICE-TOO-LOW (err u102))
(define-constant CONTRACT-OWNER tx-sender)

(define-data-var royalty uint u250)
(define-data-var royalty-address principal 'SP2KAF9RF86PVX3NEE27DFV1CQX0T4WGR41X3S45C)
(define-data-var active bool true)
(define-data-var list-cost uint u2000000)

(define-map bids { namespace: (buff 20), name: (buff 48) } { buyer: principal, offer: uint })
(define-map listings { namespace: (buff 20), name: (buff 48) } { seller: principal, ask: uint })

(define-public (bid (namespace (buff 20))
                            (domain (buff 48))
                            (amount uint))
    (let (
      (prev-offer (get offer (unwrap-panic (get-bid namespace domain))))
      (prev-buyer (get buyer (unwrap-panic (get-bid namespace domain))))
    )
    (if (is-none prev-offer)
      (match (stx-transfer? amount tx-sender (as-contract tx-sender))
        success (begin
        (asserts! (var-get active) ERR-NOT-ACTIVE)
        (asserts! (> amount u0) ERR-BID-NOT-HIGH-ENOUGH)
      (map-set bids { namespace: namespace, name: domain } { buyer: tx-sender, offer: amount })
      (ok true)
      )
      error (err error)
      )
      (match (stx-transfer? amount tx-sender (as-contract tx-sender))
        success (begin
        (asserts! (var-get active) ERR-NOT-ACTIVE)
        (asserts! (> amount (unwrap-panic prev-offer)) ERR-BID-NOT-HIGH-ENOUGH)
      (map-set bids { namespace: namespace, name: domain } { buyer: tx-sender, offer: amount })
      (try! (as-contract (stx-transfer? (unwrap-panic prev-offer) (as-contract tx-sender) (unwrap-panic prev-buyer))))
      (ok true)
      )
      error (err error)
      )
    )
    )
)

(define-public (get-bid (namespace (buff 20))
                            (domain (buff 48)))
     (ok (map-get? bids { namespace: namespace, name: domain } ))
)

(define-public (get-listing (namespace (buff 20))
                            (domain (buff 48)))
     (ok (map-get? listings { namespace: namespace, name: domain } ))
)

(define-public (withdraw-bid (namespace (buff 20))
                            (domain (buff 48)))
    (let (
        (name (map-get? bids { namespace: namespace, name: domain } ))
        (offer (unwrap-panic (get offer name)))
        (buyer (unwrap-panic (get buyer name)))
    )
    (begin
    (asserts! (var-get active) ERR-NOT-ACTIVE)
    (asserts! (is-eq tx-sender buyer) ERR-NOT-BUYER)
    (try! (as-contract (stx-transfer? offer (as-contract tx-sender) buyer)))
     (map-delete bids { namespace: namespace, name: domain } )
    )
    (ok true)
)
)

(define-public (accept-bid (namespace (buff 20))
                            (domain (buff 48))
                            (zonefile-hash (optional (buff 20))))
    (let (
        (name (map-get? bids { namespace: namespace, name: domain } ))
        (offer (unwrap-panic (get offer name)))
        (commiss (/ (* offer (var-get royalty)) u10000))
        (buyer (unwrap-panic (get buyer name)))
        (owner (get owner (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.bns name-resolve namespace domain))))
    )
    (begin
    (print commiss)
    (print name)
    (print buyer)
    (asserts! (var-get active) ERR-NOT-ACTIVE)
    (asserts! (is-eq owner tx-sender) ERR-NOT-AUTHORIZED)
    (try! (as-contract (stx-transfer? commiss (as-contract tx-sender) (var-get royalty-address))))
    (try! (as-contract (stx-transfer? (- offer commiss) (as-contract tx-sender) owner)))
    (try! (match (contract-call? 'SP000000000000000000002Q6VF78.bns name-transfer namespace domain buyer zonefile-hash)
     success (ok success) 
     error (err (to-uint error))))
     (map-delete bids { namespace: namespace, name: domain } )
     (map-delete listings { namespace: namespace, name: domain } )
    )
    (ok true)
)
)          

(define-public (list-domain (namespace (buff 20))
                            (domain (buff 48))
                            (amount uint))
    (let (
        (owner (get owner (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.bns name-resolve namespace domain))))
    )
    (begin
    (asserts! (is-eq owner tx-sender) ERR-NOT-AUTHORIZED)
    (map-set listings { namespace: namespace, name: domain } { seller: tx-sender, ask: amount })
    (try! (as-contract (stx-transfer? (var-get list-cost) tx-sender CONTRACT-OWNER)))
    (ok true)
    )
)
)

(define-public (unlist-domain (namespace (buff 20))
                            (domain (buff 48)))
    (let (
        (owner (get owner (unwrap-panic (contract-call? 'SP000000000000000000002Q6VF78.bns name-resolve namespace domain))))
    )
    (begin
    (asserts! (is-eq owner tx-sender) ERR-NOT-AUTHORIZED)
    (map-delete listings { namespace: namespace, name: domain } )
    (ok true)
    )
)
)

(define-public (admin-unbid (namespace (buff 20))
                            (domain (buff 48)))
    (let (
        (name (map-get? bids { namespace: namespace, name: domain } ))
        (offer (unwrap-panic (get offer name)))
        (buyer (unwrap-panic (get buyer name)))
    )
    (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-OWNER)
    (try! (as-contract (stx-transfer? offer (as-contract tx-sender) buyer)))
     (map-delete bids { namespace: namespace, name: domain } )
     (ok true)
    )
)
)

(define-public (admin-unlist (namespace (buff 20))
                            (domain (buff 48)))
    (begin
    (asserts! (is-eq tx-sender CONTRACT-OWNER) ERR-NOT-OWNER)
    (map-delete listings { namespace: namespace, name: domain } )
     (ok true)
    )
)

(define-public (set-list-cost (value uint))
  (if (is-eq tx-sender CONTRACT-OWNER)
    (ok (var-set list-cost value))
    (err ERR-NOT-AUTHORIZED)
  )
)

(define-public (set-royalty (value uint))
  (if (is-eq tx-sender CONTRACT-OWNER)
    (ok (var-set royalty value))
    (err ERR-NOT-AUTHORIZED)
  )
)

(define-public (set-royalty-address (address principal))
  (if (is-eq tx-sender CONTRACT-OWNER)
    (ok (var-set royalty-address address))
    (err ERR-NOT-AUTHORIZED)
  )
)

(define-public (set-active (value bool))
  (if (is-eq tx-sender CONTRACT-OWNER)
    (ok (var-set active value))
    (err ERR-NOT-AUTHORIZED)
  )
)