JavaScript (ES12), 478 bytes
s=>(a=s.split(/(\[.+?\])/)).map(S=(s,i)=>i&1?([,C,t,,p]=/.(\/)?(\w+)(=(.+))?./.exec(s),n=`url|color|size|b|i|quote|img|u|s|code`.split`|`.indexOf(t=t.toLowerCase()),C)?!([j,p]=S[t]?.pop()||[],T=`|a href="0"||21:0"||2font-1:0"|strong||em||block1|block1><cite>0</cite|1 src="0"||u||s||1`.split`|`[n*2|!!p||1]?.replace(/\d/g,n=>[p||a[j+1],t,'span style="'][n]),c-=c&&n>8)*j&&T?a[a[j]=`<${T}>`,i]=n-6?`</${/\w+/.exec(T)}>`:a[j+1]='':0:(c+=n>8,S[t]||=[]).push([i,p]):0,c=0)&&a.join``
Attempt This Online!
Commented
s =>
// split the input string on pseudo-legal BBCode tags '[…]'
(a = s.split(/(\[.+?\])/))
// for each part s at index i
.map(S = (s, i) =>
i & 1 ?
// if this is a tag
(
// C = 'closing tag' flag, t = tag name, p = optional parameter
[, C, t,, p] = /.(\/)?(\w+)(=(.+))?./.exec(s),
// force t to lower case and get n = internal BBCode tag ID
n =
// 0 1 2 3 4 5 6 7 8 9
`url|color|size|b|i|quote|img|u|s|code`
.split`|`
.indexOf(t = t.toLowerCase()),
C
) ?
// if this is a closing tag
!(
// attempt to retrieve j = position of the opening tag
// and p = parameter in the opening tag
[j, p] = S[t]?.pop() || [],
// T = HTML tag according to n and the presence of a parameter
T =
// 1 3 5 6 8
`|a href="0"||21:0"||2font-1:0"|strong||em||` +
// 10 11 12 14 16 18
`block1|block1><cite>0</cite|1 src="0"||u||s||1`
.split`|`
[n * 2 | !!p || 1]
// unpack: 0 -> p or a[j + 1], 1 -> t, 2 -> 'span style="'
?.replace(/\d/g, n => [ p || a[j + 1], t, 'span style="'][n]),
// decrement c if it's greater than 0 and the tag is 'code'
c -= c && n > 8
) * j && T ?
// if c is not 0, j is not 0 and T is defined,
// replace the opening tag with T
a[a[j] = `<${T}>`, i] =
n - 6 ?
// if this is not an 'img' tag, update the closing tag
// using the name extracted from T
`</${/\w+/.exec(T)}>`
:
// otherwise, clear both a[j + 1] and the closing tag
a[j + 1] = ''
:
// invalid tag: do nothing
0
:
// opening tag: increment c if the tag is 'code'
// and push [i, p] into this tag stack
(c += n > 8, S[t] ||= []).push([i, p])
:
// this is not a tag: do nothing
0,
// c = code block counter, initialized to 0
c = 0
)
// end of map(), return a[] joined
&& a.join``