function loginAsAdmin(): void {
  cy.visit('/login')

  cy.get('[data-cy="login-email"]').type('admin@rabbigerzi.test')
  cy.get('[data-cy="login-password"]').type('password123!@#')
  cy.get('[data-cy="login-submit"]').click()

  cy.url().should('eq', Cypress.config().baseUrl + '/')
  cy.getCookie('auth_token').should('exist')
}

function fillElementForm(
  title: string,
  description: string,
  richText: string,
  youtubeUrl: string,
): void {
  cy.get('[data-cy="admin-element-title"]').clear().type(title)
  cy.get('[data-cy="admin-element-description"]').clear().type(description)
  clearRichText()
  if (richText !== '') {
    cy.get('[data-cy="admin-element-rich-text"]').type(richText)
  }
  cy.get('[data-cy="admin-element-youtube-url"]').clear()
  if (youtubeUrl !== '') {
    cy.get('[data-cy="admin-element-youtube-url"]').type(youtubeUrl)
  }
}

function clearRichText(): void {
  cy.get('[data-cy="admin-element-rich-text"]')
    .click()
    .type('{selectAll}{backspace}')
}

describe('admin element editing', () => {
  it('does not show the edit link to logged-out users', () => {
    cy.visit('/element/1')

    cy.contains('header.site-header a', 'Edit Element').should('not.exist')
  })

  it('shows the edit link on public element pages to logged-in users', () => {
    loginAsAdmin()

    cy.visit('/element/1')

    cy.contains('header.site-header a', 'Edit Element')
      .should('be.visible')
      .and('have.attr', 'href', '/admin/element/1')
      .click()
    cy.location('pathname').should('eq', '/admin/element/1')
  })

  it('redirects logged-out admin element visits to login', () => {
    cy.visit('/admin/element/1')

    cy.location('pathname').should('eq', '/login')
  })

  it('shows the view link on admin element pages', () => {
    loginAsAdmin()

    cy.visit('/admin/element/1')

    cy.contains('header.site-header a', 'View Element')
      .should('be.visible')
      .and('have.attr', 'href', '/element/1')
    cy.contains('header.site-header a', 'Edit Element').should('not.exist')
    cy.get('[data-cy="admin-element-title"]')
      .should('have.value', 'Baderech HaAvodah')
  })

  it('saves element edits and restores the seed content through the UI', () => {
    const originalTitle = 'Baderech HaAvodah'
    const originalDescription = 'a structured path for inner and outer growth'
    const updatedTitle = 'Baderech HaAvodah Updated'
    const updatedDescription = 'Updated admin description'

    loginAsAdmin()
    cy.visit('/admin/element/1')

    fillElementForm(
      updatedTitle,
      updatedDescription,
      '',
      '',
    )
    cy.get('[data-cy="admin-element-rich-text"]')
      .should('have.attr', 'contenteditable', 'true')

    cy.get('[data-cy="admin-rich-text-block-type"]').select('heading-2')
    cy.get('[data-cy="admin-element-rich-text"]')
      .type('Updated admin heading{enter}')
    cy.get('[data-cy="admin-rich-text-bold"]').click()
    cy.get('[data-cy="admin-element-rich-text"]').type('Strong admin text')
    cy.get('[data-cy="admin-rich-text-bold"]').click()
    cy.get('[data-cy="admin-element-rich-text"]').type('{enter}')
    cy.get('[data-cy="admin-rich-text-bullet-list"]').click()
    cy.get('[data-cy="admin-element-rich-text"]')
      .type('First saved item{enter}Second saved item')
    cy.get('[data-cy="admin-rich-text-bullet-list"]').click()
    cy.window().then((windowObject) => {
      cy.stub(windowObject, 'prompt').returns('https://example.com/rich-text')
    })
    cy.get('[data-cy="admin-rich-text-link"]').click()
    cy.get('[data-cy="admin-rich-text-insert-table"]').click()
    cy.get('[data-cy="admin-element-save"]').click()

    cy.get('[data-cy="admin-element-status"]')
      .should('be.visible')
      .and('contain.text', 'Saved')
    cy.contains('header.site-header a', 'View Element').click()
    cy.location('pathname').should('eq', '/element/1')
    cy.contains('h1', updatedTitle).should('be.visible')
    cy.get('[data-cy="element-rich-text"] h2')
      .should('contain.text', 'Updated admin heading')
    cy.get('[data-cy="element-rich-text"] strong')
      .should('contain.text', 'Strong admin text')
    cy.get('[data-cy="element-rich-text"]')
      .should('contain.text', 'First saved item')
      .and('contain.text', 'Second saved item')
    cy.get('[data-cy="element-rich-text"] a')
      .should('have.attr', 'href', 'https://example.com/rich-text')
    cy.get('[data-cy="element-rich-text"] table').should('exist')

    cy.visit('/admin/element/1')
    fillElementForm(
      originalTitle,
      originalDescription,
      '',
      '',
    )
    cy.get('[data-cy="admin-element-save"]').click()
    cy.get('[data-cy="admin-element-status"]')
      .should('be.visible')
      .and('contain.text', 'Saved')
    cy.contains('header.site-header a', 'View Element').click()
    cy.get('[data-cy="element-rich-text"]').should('not.exist')
  })

  it('adds a child element and opens it for editing', () => {
    cy.resetDb()
    loginAsAdmin()
    cy.visit('/admin/element/1')
    cy.intercept('POST', /\/api\/elements\/1\/children$/)
      .as('createChildElement')

    cy.get('[data-cy="admin-child-title"]').type('Admin added child')
    cy.get('[data-cy="admin-add-child"]').click()
    cy.wait('@createChildElement')

    cy.location('pathname').should('match', /^\/admin\/element\/\d+$/)
    cy.get('[data-cy="admin-element-title"]')
      .should('have.value', 'Admin added child')
    cy.contains('header.site-header a', 'View Element').click()
    cy.contains('h1', 'Admin added child').should('be.visible')

    cy.visit('/element/1')
    cy.get('[data-cy="child-element-list"]')
      .should('contain.text', 'Admin added child')

    cy.resetDb()
  })

  it('removes a child element after confirmation', () => {
    cy.resetDb()
    loginAsAdmin()
    cy.visit('/admin/element/1')
    cy.intercept('DELETE', /\/api\/elements\/1\/children\/\d+$/)
      .as('deleteChildElement')
    cy.window().then((windowObject) => {
      cy.stub(windowObject, 'confirm').returns(true)
    })

    cy.contains('[data-cy="admin-child-item"]', '1. Introduction')
      .within(() => {
        cy.contains('button', 'Remove').click()
      })
    cy.wait('@deleteChildElement')

    cy.get('[data-cy="admin-child-status"]')
      .should('be.visible')
      .and('contain.text', 'Child element removed')
    cy.contains('[data-cy="admin-child-item"]', '1. Introduction')
      .should('not.exist')
    cy.contains('header.site-header a', 'View Element').click()
    cy.get('[data-cy="child-element-list"]')
      .should('not.contain.text', '1. Introduction')

    cy.resetDb()
  })

  it('reorders child elements through admin controls', () => {
    cy.resetDb()
    loginAsAdmin()
    cy.visit('/admin/element/1')
    cy.intercept('PUT', /\/api\/elements\/1\/children\/order$/)
      .as('reorderChildElements')

    cy.contains('[data-cy="admin-child-item"]', '2. Foundations')
      .within(() => {
        cy.get('[data-cy="admin-move-child-up"]').click()
      })
    cy.wait('@reorderChildElements')

    cy.get('[data-cy="admin-child-status"]')
      .should('be.visible')
      .and('contain.text', 'Child order saved')
    cy.get('[data-cy="admin-child-item"]')
      .eq(0)
      .should('contain.text', '2. Foundations')
    cy.get('[data-cy="admin-child-item"]')
      .eq(1)
      .should('contain.text', '1. Introduction')

    cy.contains('header.site-header a', 'View Element').click()
    cy.get('[data-cy="child-element-link"]')
      .eq(0)
      .should('contain.text', '2. Foundations')
    cy.get('[data-cy="child-element-link"]')
      .eq(1)
      .should('contain.text', '1. Introduction')

    cy.visit('/element/3')
    cy.get('[data-cy="element-sibling-previous"]')
      .should('have.attr', 'href', '/element/7')
    cy.get('[data-cy="element-sibling-next"]')
      .should('have.attr', 'href', '/element/2')

    cy.resetDb()
  })

  it('uploads icon and pdf files immediately through the UI', () => {
    cy.resetDb()
    loginAsAdmin()
    cy.visit('/admin/element/1')
    cy.intercept('POST', /\/api\/element\/update$/).as('updateElement')

    cy.get('[data-cy="admin-element-icon-image-input"]').selectFile(
      'public/assets/baderech-haavodah-icon.png',
      { force: true },
    )
    cy.wait('@updateElement')
    cy.get('[data-cy="admin-element-icon-image-status"]')
      .should('be.visible')
      .and('contain.text', 'Icon image updated')
    cy.get('[data-cy="admin-element-current-icon"]')
      .should('be.visible')
      .and('have.attr', 'src')
      .and('include', '/storage/element-icons/')

    cy.get('[data-cy="admin-element-short-pdf-input"]').selectFile(
      'public/assets/pdfs/baderech.pdf',
      { force: true },
    )
    cy.wait('@updateElement')
    cy.get('[data-cy="admin-element-short-pdf-status"]')
      .should('be.visible')
      .and('contain.text', 'Short PDF updated')
    cy.get('[data-cy="admin-element-current-short-pdf"]')
      .should('be.visible')
      .and('have.attr', 'href')
      .and('include', '/storage/element-pdfs/short/')

    cy.get('[data-cy="admin-element-long-pdf-input"]').selectFile(
      'public/assets/pdfs/baderech.pdf',
      { force: true },
    )
    cy.wait('@updateElement')
    cy.get('[data-cy="admin-element-long-pdf-status"]')
      .should('be.visible')
      .and('contain.text', 'Long PDF updated')
    cy.get('[data-cy="admin-element-current-long-pdf"]')
      .should('be.visible')
      .and('have.attr', 'href')
      .and('include', '/storage/element-pdfs/long/')

    cy.contains('header.site-header a', 'View Element').click()
    cy.get('[data-cy="element-icon"]')
      .should('be.visible')
      .and('have.attr', 'src')
      .and('include', '/storage/element-icons/')
    cy.get('[data-cy="element-short-pdf-viewer-button"]')
      .should('be.visible')
      .and('contain.text', 'View Short PDF')
    cy.get('[data-cy="element-long-pdf-viewer-button"]')
      .should('be.visible')
      .and('contain.text', 'View Long PDF')

    cy.resetDb()
  })

  it('removes uploaded icon and pdf files immediately through the UI', () => {
    cy.resetDb()
    loginAsAdmin()
    cy.visit('/admin/element/1')
    cy.intercept('POST', /\/api\/element\/update$/).as('updateElement')

    cy.get('[data-cy="admin-element-icon-image-input"]').selectFile(
      'public/assets/baderech-haavodah-icon.png',
      { force: true },
    )
    cy.wait('@updateElement')
    cy.get('[data-cy="admin-element-short-pdf-input"]').selectFile(
      'public/assets/pdfs/baderech.pdf',
      { force: true },
    )
    cy.wait('@updateElement')
    cy.get('[data-cy="admin-element-long-pdf-input"]').selectFile(
      'public/assets/pdfs/baderech.pdf',
      { force: true },
    )
    cy.wait('@updateElement')

    cy.contains('button', 'Remove icon image').click()
    cy.wait('@updateElement')
    cy.get('[data-cy="admin-element-icon-image-status"]')
      .should('be.visible')
      .and('contain.text', 'Icon image removed')
    cy.get('[data-cy="admin-element-current-icon"]').should('not.exist')
    cy.contains('No icon image').should('be.visible')

    cy.contains('button', 'Remove short PDF').click()
    cy.wait('@updateElement')
    cy.get('[data-cy="admin-element-short-pdf-status"]')
      .should('be.visible')
      .and('contain.text', 'Short PDF removed')
    cy.get('[data-cy="admin-element-current-short-pdf"]').should('not.exist')
    cy.contains('No short PDF').should('be.visible')

    cy.contains('button', 'Remove long PDF').click()
    cy.wait('@updateElement')
    cy.get('[data-cy="admin-element-long-pdf-status"]')
      .should('be.visible')
      .and('contain.text', 'Long PDF removed')
    cy.get('[data-cy="admin-element-current-long-pdf"]').should('not.exist')
    cy.contains('No long PDF').should('be.visible')

    cy.contains('header.site-header a', 'View Element').click()
    cy.get('[data-cy="element-icon"]').should('not.exist')
    cy.get('[data-cy="element-short-pdf-viewer-button"]').should('not.exist')
    cy.get('[data-cy="element-long-pdf-viewer-button"]').should('not.exist')

    cy.resetDb()
  })
})
