'use client'

import {useState, useEffect, useRef} from 'react'
import PropTypes from 'prop-types'
import {styled, useTheme, useColorScheme} from '@mui/material/styles'
import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import Slider from '@mui/material/Slider'
import IconButton from '@mui/material/IconButton'
import Stack from '@mui/material/Stack'
import PauseRounded from '@mui/icons-material/PauseRounded'
import PlayArrowRounded from '@mui/icons-material/PlayArrowRounded'
import VolumeUpRounded from '@mui/icons-material/VolumeUpRounded'
import VolumeDownRounded from '@mui/icons-material/VolumeDownRounded'
import Image from 'next/image'
import {grey} from '@mui/material/colors'
import {Link} from '@mui/material'

import {getAlias} from '../../lib/utils/get-alias'
import {formatKuveti} from '../../lib/kuveti'

const IMAGE_URL = process.env.NEXT_PUBLIC_API_URL_ROOT || 'http://localhost:1337'

function createAudio(src) {
  const audio = new Audio(src)
  audio.preload = 'metadata'
  return audio
}

function parseLrc(text) {
  const lines = []
  for (const raw of text.split('\n')) {
    const match = raw.match(/^\[(\d{2}):(\d{2})[.:]\d+](.*)$/)
    if (match) {
      const time = (Number.parseInt(match[1], 10) * 60) + Number.parseInt(match[2], 10)
      lines.push({time, text: match[3].trim()})
    }
  }

  return lines.sort((a, b) => a.time - b.time).filter(l => l.text)
}

const Widget = styled('div')(({theme}) => ({
  padding: 16,
  borderRadius: 16,
  width: 343,
  maxWidth: '100%',
  margin: 'auto',
  position: 'relative',
  zIndex: 1,
  backgroundColor: grey[200],
  ...theme.applyStyles('dark', {
    backgroundColor: 'rgba(0,0,0,0.6)'
  }),
  backdropFilter: 'blur(40px)',
}))

const CoverImage = styled('div')({
  width: 100,
  height: 100,
  objectFit: 'cover',
  overflow: 'hidden',
  flexShrink: 0,
  borderRadius: 8,
  backgroundColor: 'rgba(0,0,0,0.08)',
  '& > img': {
    width: '100%',
  },
})

const TinyText = styled(Typography)({
  fontSize: '0.75rem',
  opacity: 0.38,
  fontWeight: 500,
  letterSpacing: 0.2,
})

export default function Lekte({audio, url, parole}) {
  const audioRef = useRef(null)
  if (audioRef.current === null) {
    audioRef.current = createAudio(audio)
  }

  const intervalRef = useRef()
  const [duration, setDuration] = useState(0)
  const theme = useTheme()
  const {mode} = useColorScheme()
  const [position, setPosition] = useState(0)
  const [volume, setVolume] = useState(100)
  const [isPlaying, setIsPlaying] = useState(false)
  const [lrcLines, setLrcLines] = useState(null)
  const alias = getAlias(parole.artistes, parole.prioriteArtistes)

  function formatDuration(value) {
    const minute = Math.floor(value / 60)
    const secondLeft = value - (minute * 60)
    if (Number.isNaN(minute) || Number.isNaN(secondLeft)) {
      return '...'
    }

    return `${minute}:${secondLeft <= 9 ? `0${secondLeft}` : secondLeft}`
  }

  const mainIconColor = mode === 'dark' ? '#fff' : '#000'
  const lightIconColor = mode === 'dark' ? 'rgba(255,255,255,0.4)' : grey[900]

  const startTimer = () => {
    clearInterval(intervalRef.current)
    intervalRef.current = setInterval(() => {
      setPosition(Math.round(audioRef.current.currentTime))
    }, 1000)
  }

  useEffect(() =>
    () => {
      audioRef.current.pause()
      clearInterval(intervalRef.current)
    }
  , [])

  useEffect(() => {
    if (isPlaying) {
      audioRef.current.play().catch(() => {})
      startTimer()
    } else {
      clearInterval(intervalRef.current)
      audioRef.current.pause()
    }
  }, [isPlaying])

  useEffect(() => {
    audioRef.current.pause()
    audioRef.current = createAudio(audio)
    setIsPlaying(false)
    setVolume(100)
    setPosition(0)
    setDuration(0)
  }, [audio])

  useEffect(() => {
    const el = audioRef.current
    const onLoaded = () => setDuration(Math.round(el.duration))
    const onEnded = () => {
      clearInterval(intervalRef.current)
      setIsPlaying(false)
      setPosition(0)
      el.currentTime = 0
    }

    el.addEventListener('loadedmetadata', onLoaded)
    el.addEventListener('ended', onEnded)
    return () => {
      el.removeEventListener('loadedmetadata', onLoaded)
      el.removeEventListener('ended', onEnded)
    }
  }, [audio])

  useEffect(() => {
    if (!parole?.pawol?.url) {
      return
    }

    fetch(new URL(parole.pawol.url, IMAGE_URL).toString())
      .then(r => r.text())
      .then(text => setLrcLines(parseLrc(text)))
      .catch(() => setLrcLines([]))
  }, [parole?.pawol?.url])

  const activeIndex = lrcLines
    ? lrcLines.findLastIndex(line => line.time <= position)
    : -1

  const handleChangePosition = value => {
    setPosition(value)
    audioRef.current.currentTime = value
  }

  const handleChangeVolume = value => {
    setVolume(value)
    audioRef.current.volume = value / 100
  }

  const couvertureFormat = formatKuveti(parole?.couverture, 'thumbnail')
  const imagePath = couvertureFormat?.url
  const width = couvertureFormat?.width || 192
  const height = couvertureFormat?.height || 192

  const imageSrc = imagePath
    ? new URL(imagePath, IMAGE_URL).toString()
    : '/logo-192x192.png'

  return (
    <Box sx={{width: '80%', position: 'relative', zIndex: 0}}>
      <Widget>
        <Box sx={{display: 'flex', alignItems: 'center'}}>
          <CoverImage>
            <Image
              alt={parole.titre}
              src={imageSrc}
              width={width}
              height={height}
            />
          </CoverImage>
          <Box sx={{ml: 1.5, minWidth: 0}}>
            <Typography fontWeight={500}>
              {alias}
            </Typography>
            <Typography>
              <Link underline='hover' sx={{cursor: 'pointer'}} target='_blank' rel='noreferrer' href={url}>
                <strong>{parole.titre}</strong>
              </Link>
            </Typography>
            <Typography variant='caption'>
              <i>{parole.annee}</i>
            </Typography>
          </Box>
        </Box>
        <Slider
          aria-label='time-indicator'
          size='small'
          defaultValue={position}
          value={position || 0}
          min={0}
          step={1}
          max={duration || 100}
          sx={{
            color: 'rgba(0,0,0,0.87)',
            ...theme.applyStyles('dark', {
              color: '#fff'
            }),
            height: 4,
            '& .MuiSlider-thumb': {
              width: 8,
              height: 8,
              transition: '0.3s cubic-bezier(.47,1.64,.41,.8)',
              '&:before': {
                boxShadow: '0 2px 12px 0 rgba(0,0,0,0.4)',
              },
              '&:hover, &.Mui-focusVisible': {
                boxShadow: `0px 0px 0px 8px ${
                  theme.palette.mode === 'dark'
                    ? 'rgb(255 255 255 / 16%)'
                    : 'rgb(0 0 0 / 16%)'
                }`,
              },
              '&.Mui-active': {
                width: 20,
                height: 20,
              },
            },
            '& .MuiSlider-rail': {
              opacity: 0.28,
            },
          }}
          onChange={(_, value) => handleChangePosition(value)}
        />
        <Box
          sx={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'space-between',
            mt: -2,
          }}
        >
          <TinyText>{formatDuration(position)}</TinyText>
          <TinyText>-{formatDuration(Math.round(duration) - position)}</TinyText>
        </Box>
        <Box
          sx={{
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            mt: -1,
          }}
        >
          <IconButton
            aria-label={isPlaying ? 'pause' : 'play'}
            onClick={() => setIsPlaying(!isPlaying)}
          >
            {isPlaying ? (
              <PauseRounded sx={{fontSize: '3rem'}} htmlColor={mainIconColor} />
            ) : (
              <PlayArrowRounded
                sx={{fontSize: '3rem'}}
                htmlColor={mainIconColor}
              />
            )}
          </IconButton>
        </Box>
        <Stack spacing={2} direction='row' sx={{mb: 1, px: 1}} alignitems='center'>
          <VolumeDownRounded htmlColor={lightIconColor} />
          <Slider
            aria-label='Volume'
            defaultValue={volume}
            value={volume}
            sx={{
              color: 'rgba(0,0,0,0.87)',
              ...theme.applyStyles('dark', {
                color: '#fff'
              }),
              '& .MuiSlider-track': {
                border: 'none',
              },
              '& .MuiSlider-thumb': {
                width: 24,
                height: 24,
                backgroundColor: '#fff',
                '&:before': {
                  boxShadow: '0 4px 8px rgba(0,0,0,0.4)',
                },
                '&:hover, &.Mui-focusVisible, &.Mui-active': {
                  boxShadow: 'none',
                },
              },
            }}
            onChange={(_, value) => handleChangeVolume(value)}
          />
          <VolumeUpRounded htmlColor={lightIconColor} />
        </Stack>
        {lrcLines && lrcLines.length > 0 && (
          <Box sx={{mt: 1.5, textAlign: 'center', minHeight: 64}}>
            {[-1, 0, 1].map(offset => {
              const idx = activeIndex + offset
              const line = lrcLines[idx]
              if (!line) {
                return <Box key={offset} sx={{height: offset === 0 ? 28 : 20}} />
              }

              return (
                <Typography
                  key={offset}
                  variant={offset === 0 ? 'body2' : 'caption'}
                  sx={{
                    display: 'block',
                    fontWeight: offset === 0 ? 'bold' : 'normal',
                    color: offset === 0 ? 'text.primary' : 'text.secondary',
                    opacity: offset === 0 ? 1 : 0.45,
                    transition: 'all 0.3s ease',
                    lineHeight: offset === 0 ? 1.6 : 1.4,
                  }}
                >
                  {line.text}
                </Typography>
              )
            })}
          </Box>
        )}
      </Widget>
    </Box>
  )
}

Lekte.propTypes = {
  audio: PropTypes.string.isRequired,
  url: PropTypes.string.isRequired,
  parole: PropTypes.object.isRequired
}
