import { Hono } from 'hono'
import { cors } from 'hono/cors'
import { serveStatic } from 'hono/cloudflare-workers'
import { authMiddleware, optionalAuthMiddleware } from './middleware/auth'
import { generateToken, verifyPassword, hashPassword } from './utils/auth'
import { ORIGINAL_HTML } from './original-html'

type Bindings = {
  DB: D1Database;
}

type Variables = {
  userId?: number;
  username?: string;
  role?: string;
}

const app = new Hono<{ Bindings: Bindings; Variables: Variables }>()

// Enable CORS
app.use('/api/*', cors())

// Serve static files
app.use('/static/*', serveStatic({ root: './public' }))
// Serve favicon (empty response to avoid 404)
app.get('/favicon.ico', (c) => {
  return new Response(null, { status: 204 })
})

// ==================== AUTH ROUTES ====================

// Login endpoint
app.post('/api/auth/login', async (c) => {
  try {
    const { username, password } = await c.req.json()
    
    const user = await c.env.DB.prepare(
      'SELECT id, username, password_hash, full_name, role FROM users WHERE username = ? AND deleted_at IS NULL'
    ).bind(username).first()

    if (!user || !await verifyPassword(password, user.password_hash as string)) {
      return c.json({ error: 'Invalid credentials' }, 401)
    }

    const token = generateToken(user.id as number, user.username as string)
    
    return c.json({
      success: true,
      token,
      user: {
        username: user.username,
        fullName: user.full_name,
        role: user.role
      }
    })
  } catch (error) {
    console.error('Login error:', error)
    return c.json({ error: 'Login failed' }, 500)
  }
})

// Update user profile (password change)
app.patch('/api/users/profile', authMiddleware, async (c) => {
  try {
    const body = await c.req.json()
    const fullName = body.full_name || body.fullName
    const currentPassword = body.current_password || body.currentPassword
    const newPassword = body.new_password || body.newPassword
    const userId = c.get('userId')

    console.log('[PROFILE UPDATE]', { userId, fullName, hasCurrentPwd: !!currentPassword, hasNewPwd: !!newPassword })

    // Get user from database
    const user = await c.env.DB.prepare(
      'SELECT password_hash, full_name FROM users WHERE id = ?'
    ).bind(userId).first()

    if (!user) {
      return c.json({ error: 'Kasutajat ei leitud' }, 404)
    }

    // If changing password
    if (newPassword) {
      // Verify current password is provided
      if (!currentPassword) {
        return c.json({ error: 'Praegune parool on kohustuslik parooli muutmiseks' }, 400)
      }

      // Verify current password
      if (!await verifyPassword(currentPassword, user.password_hash as string)) {
        return c.json({ error: 'Vale praegune parool' }, 400)
      }

      // Update password and full name
      const newHash = await hashPassword(newPassword)
      await c.env.DB.prepare(
        'UPDATE users SET password_hash = ?, full_name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?'
      ).bind(newHash, fullName, userId).run()
    } else {
      // Only update full name (no password change)
      await c.env.DB.prepare(
        'UPDATE users SET full_name = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?'
      ).bind(fullName, userId).run()
    }

    return c.json({ 
      success: true, 
      message: 'Profiil uuendatud',
      user: {
        full_name: fullName
      }
    })
  } catch (error) {
    console.error('Profile update error:', error)
    return c.json({ error: 'Profiili uuendamine ebaõnnestus' }, 500)
  }
})

// ==================== DATA ROUTES ====================

// Get years for dropdown (with optional auth)
app.get('/api/years', optionalAuthMiddleware, async (c) => {
  try {
    const result = await c.env.DB.prepare(
      'SELECT MIN(year) as min_year FROM production_records WHERE deleted_at IS NULL'
    ).first()
    
    const minYear = result?.min_year || new Date().getFullYear()
    const maxYear = new Date().getFullYear() + 1
    
    // Create array of years from minYear to maxYear
    const years = []
    for (let year = minYear; year <= maxYear; year++) {
      years.push(year)
    }
    
    return c.json({ years })
  } catch (error) {
    console.error('Error fetching years:', error)
    return c.json({ error: 'Failed to fetch years' }, 500)
  }
})

// Get records (with optional auth for token refresh)
app.get('/api/records', optionalAuthMiddleware, async (c) => {
  try {
    const month = c.req.query('month')
    const year = c.req.query('year')

    if (!month || !year) {
      return c.json({ error: 'Month and year required' }, 400)
    }

    const records = await c.env.DB.prepare(`
      SELECT 
        pr.*,
        sc.material_date,
        sc.material2_date,
        sc.package_date,
        sc.worksheets_date,
        sc.cutting_date,
        sc.glazing_date,
        sc.ready_date,
        sc.issued_date,
        sc.worksheets_error,
        sc.cutting_error,
        sc.glazing_error,
        sc.ready_error,
        sc.issued_error,
        sc.material_confirmed,
        sc.material2_confirmed,
        sc.worksheets_confirmed
      FROM production_records pr
      LEFT JOIN status_checkboxes sc ON pr.id = sc.record_id
      WHERE pr.month = ? AND pr.year = ? AND pr.deleted_at IS NULL
      ORDER BY pr.created_at DESC
    `).bind(month, year).all()

    return c.json(records.results || [])
  } catch (error) {
    console.error('Error fetching records:', error)
    return c.json({ error: 'Failed to fetch records' }, 500)
  }
})

// Create new record
app.post('/api/records', optionalAuthMiddleware, async (c) => {
  try {
    const data = await c.req.json()
    const userId = c.get('userId')
    
    // Validate and convert numeric fields
    const quantity = data.quantity ? parseInt(data.quantity, 10) : 0
    const price = data.price ? parseFloat(data.price) : 0
    
    const result = await c.env.DB.prepare(`
      INSERT INTO production_records (
        month, year, client_name, type, offer_number, work_number,
        quantity, color, notes, problems, installer, price,
        created_by, updated_by
      ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `).bind(
      data.month, data.year, data.client_name, data.type || null,
      data.offer_number, data.work_number, quantity, data.color || null,
      data.notes || null, data.problems || null, data.installer || null,
      price, userId, userId
    ).run()

    // Create status checkboxes entry
    await c.env.DB.prepare(`
      INSERT INTO status_checkboxes (record_id) VALUES (?)
    `).bind(result.meta.last_row_id).run()

    return c.json({ success: true, id: result.meta.last_row_id })
  } catch (error) {
    console.error('Error creating record:', error)
    return c.json({ error: 'Failed to create record' }, 500)
  }
})

// Update record
app.put('/api/records/:id', optionalAuthMiddleware, async (c) => {
  try {
    const id = c.req.param('id')
    const data = await c.req.json()
    const userId = c.get('userId')

    // Validate and convert numeric fields
    const quantity = data.quantity ? parseInt(data.quantity, 10) : 0
    const price = data.price ? parseFloat(data.price) : 0

    await c.env.DB.prepare(`
      UPDATE production_records 
      SET client_name = ?, type = ?, offer_number = ?, work_number = ?,
          quantity = ?, color = ?, notes = ?, problems = ?, installer = ?, price = ?,
          updated_by = ?, updated_at = CURRENT_TIMESTAMP
      WHERE id = ? AND deleted_at IS NULL
    `).bind(
      data.client_name, data.type || null, data.offer_number, data.work_number,
      quantity, data.color || null, data.notes || null, data.problems || null,
      data.installer || null, price, userId, id
    ).run()

    // Update status_checkboxes dates if provided
    if (data.material_date !== undefined || data.material2_date !== undefined || data.package_date !== undefined) {
      // Convert empty strings and "null" strings to actual NULL
      const materialDate = (data.material_date && data.material_date !== 'null') ? data.material_date : null
      const material2Date = (data.material2_date && data.material2_date !== 'null') ? data.material2_date : null
      const packageDate = (data.package_date && data.package_date !== 'null') ? data.package_date : null

      await c.env.DB.prepare(`
        UPDATE status_checkboxes 
        SET material_date = ?,
            material2_date = ?,
            package_date = ?,
            updated_at = CURRENT_TIMESTAMP
        WHERE record_id = ?
      `).bind(materialDate, material2Date, packageDate, id).run()
    }

    return c.json({ success: true })
  } catch (error) {
    console.error('Error updating record:', error)
    return c.json({ error: 'Failed to update record' }, 500)
  }
})

// Get single record
app.get('/api/records/:id', optionalAuthMiddleware, async (c) => {
  try {
    const id = c.req.param('id')
    
    const record = await c.env.DB.prepare(`
      SELECT * FROM production_records WHERE id = ? AND deleted_at IS NULL
    `).bind(id).first()

    if (!record) {
      return c.json({ error: 'Record not found' }, 404)
    }

    return c.json(record)
  } catch (error) {
    console.error('Error fetching record:', error)
    return c.json({ error: 'Failed to fetch record' }, 500)
  }
})

// Delete record (soft delete)
app.delete('/api/records/:id', optionalAuthMiddleware, async (c) => {
  try {
    const id = c.req.param('id')
    const userId = c.get('userId')

    console.log('[DELETE] Deleting record:', id, 'by user:', userId)

    await c.env.DB.prepare(`
      UPDATE production_records 
      SET deleted_at = CURRENT_TIMESTAMP, deleted = 1
      WHERE id = ?
    `).bind(id).run()

    console.log('[DELETE] Record deleted successfully:', id)

    return c.json({ success: true })
  } catch (error) {
    console.error('Error deleting record:', error)
    return c.json({ error: 'Failed to delete record' }, 500)
  }
})

// ==================== STATUS CHECKBOX ROUTES ====================

// Toggle date - simplified endpoint for frontend compatibility
app.patch('/api/records/:id/status', optionalAuthMiddleware, async (c) => {
  try {
    const recordId = c.req.param('id')
    const { field, date } = await c.req.json()
    const userId = c.get('userId')

    console.log(`[TOGGLE] recordId=${recordId}, field=${field}, date=${JSON.stringify(date)}`)

    // Field name with _date suffix for database column
    const dbField = `${field}_date`

    // Get old date for audit
    const oldRecord = await c.env.DB.prepare(
      `SELECT ${dbField} FROM status_checkboxes WHERE record_id = ?`
    ).bind(recordId).first()

    // Check if ready or issued fields are blocked by error flags
    if (field === 'ready' || field === 'issued') {
      const statusCheckbox = await c.env.DB.prepare(
        'SELECT worksheets_error, cutting_error, glazing_error, ready_error, issued_error FROM status_checkboxes WHERE record_id = ?'
      ).bind(recordId).first()

      const hasErrorFlags = statusCheckbox && (
        statusCheckbox.worksheets_error || 
        statusCheckbox.cutting_error || 
        statusCheckbox.glazing_error || 
        statusCheckbox.ready_error || 
        statusCheckbox.issued_error
      )

      if (hasErrorFlags) {
        return c.json({ 
          error: 'blocked',
          message: 'Vigade märked on seatud (punased kolmnurgad)'
        }, 403)
      }
    }

    // Toggle logic:
    // 1. If date is null/empty → check if cell is empty → add today's date OR clear
    // 2. If date matches current date → toggle off (clear)
    // 3. Otherwise → use provided date
    let newDate: string | null
    if (!date || date === 'null') {
      // null/empty clicked
      if (oldRecord?.[dbField]) {
        // Cell has date → clear it
        newDate = null
      } else {
        // Cell is empty → add today's date
        newDate = new Date().toISOString().split('T')[0]
      }
    } else if (date === oldRecord?.[dbField]) {
      // Same date as current → toggle off (clear)
      newDate = null
    } else {
      // Different date provided → use it
      newDate = date
    }
    
    await c.env.DB.prepare(
      `UPDATE status_checkboxes SET ${dbField} = ? WHERE record_id = ?`
    ).bind(newDate, recordId).run()

    // Log to audit
    await c.env.DB.prepare(`
      INSERT INTO audit_log (user_id, record_id, field, old_value, new_value, action)
      VALUES (?, ?, ?, ?, ?, 'toggle_status')
    `).bind(userId || null, recordId, field, oldRecord?.[dbField] || null, newDate).run()

    return c.json({ success: true })
  } catch (error) {
    console.error('Error toggling status:', error)
    return c.json({ error: 'Failed to toggle status' }, 500)
  }
})

// Update status checkbox date
app.patch('/api/status/:recordId/:field', optionalAuthMiddleware, async (c) => {
  try {
    const recordId = c.req.param('id')
    const field = c.req.param('field')
    const { date } = await c.req.json()
    const userId = c.get('userId')

    // Get old date for audit
    const oldRecord = await c.env.DB.prepare(
      `SELECT ${field}_date FROM status_checkboxes WHERE record_id = ?`
    ).bind(recordId).first()

    // Check if ready or issued fields are blocked by error flags
    if (field === 'ready' || field === 'issued') {
      const statusCheckbox = await c.env.DB.prepare(
        'SELECT worksheets_error, cutting_error, glazing_error, ready_error, issued_error FROM status_checkboxes WHERE record_id = ?'
      ).bind(recordId).first()

      const hasErrorFlags = statusCheckbox && (
        statusCheckbox.worksheets_error || 
        statusCheckbox.cutting_error || 
        statusCheckbox.glazing_error || 
        statusCheckbox.ready_error || 
        statusCheckbox.issued_error
      )

      if (hasErrorFlags) {
        return c.json({ 
          error: 'Väli blokeeritud',
          blocked: true,
          reason: 'Vigade märked on seatud (punased kolmnurgad)'
        }, 400)
      }
    }

    // Update the date
    await c.env.DB.prepare(
      `UPDATE status_checkboxes SET ${field}_date = ? WHERE record_id = ?`
    ).bind(date, recordId).run()

    // Log to audit
    await c.env.DB.prepare(`
      INSERT INTO audit_log (user_id, record_id, field, old_value, new_value, action)
      VALUES (?, ?, ?, ?, ?, 'update_status')
    `).bind(userId || null, recordId, field, oldRecord?.[`${field}_date`] || null, date).run()

    return c.json({ success: true })
  } catch (error) {
    console.error('Error updating status:', error)
    return c.json({ error: 'Failed to update status' }, 500)
  }
})

// Update error flag
app.patch('/api/status/:recordId/:field/error', optionalAuthMiddleware, async (c) => {
  try {
    const recordId = c.req.param('id')
    const field = c.req.param('field')
    const { value } = await c.req.json()
    const userId = c.get('userId')

    await c.env.DB.prepare(
      `UPDATE status_checkboxes SET ${field}_error = ? WHERE record_id = ?`
    ).bind(value ? 1 : 0, recordId).run()

    return c.json({ success: true })
  } catch (error) {
    console.error('Error updating error flag:', error)
    return c.json({ error: 'Failed to update error flag' }, 500)
  }
})

// Update confirmation flag
app.patch('/api/status/:recordId/:field/confirm', optionalAuthMiddleware, async (c) => {
  try {
    const recordId = c.req.param('id')
    const field = c.req.param('field')
    const { value } = await c.req.json()
    const userId = c.get('userId')

    await c.env.DB.prepare(
      `UPDATE status_checkboxes SET ${field}_confirmed = ? WHERE record_id = ?`
    ).bind(value ? 1 : 0, recordId).run()

    return c.json({ success: true })
  } catch (error) {
    console.error('Error updating confirmation flag:', error)
    return c.json({ error: 'Failed to update confirmation flag' }, 500)
  }
})

// ==================== ADDITIONAL RECORD ROUTES ====================

// Worksheets cycle (3-step: empty -> confirmed -> with date -> empty)
app.patch('/api/records/:id/worksheets-cycle', optionalAuthMiddleware, async (c) => {
  try {
    const recordId = c.req.param('id')
    const userId = c.get('userId')

    // Get current worksheets state
    const statusRecord = await c.env.DB.prepare(
      'SELECT worksheets_date, worksheets_confirmed FROM status_checkboxes WHERE record_id = ?'
    ).bind(recordId).first()

    let newDate = null
    let newConfirmed = 0

    // 3-step cycle logic:
    // Step 1: empty (null date, confirmed=0) -> gray with date (date, confirmed=0)
    // Step 2: gray with date (date, confirmed=0) -> green with date (date, confirmed=1)
    // Step 3: green with date (date, confirmed=1) -> empty (null date, confirmed=0)
    if (!statusRecord?.worksheets_date) {
      // Step 1: empty -> gray with date
      newConfirmed = 0
      newDate = new Date().toISOString().split('T')[0]
    } else if (statusRecord.worksheets_confirmed === 0) {
      // Step 2: gray with date -> green with date
      newConfirmed = 1
      newDate = statusRecord.worksheets_date  // Keep existing date
    } else {
      // Step 3: green with date -> empty
      newConfirmed = 0
      newDate = null
    }

    await c.env.DB.prepare(
      'UPDATE status_checkboxes SET worksheets_date = ?, worksheets_confirmed = ? WHERE record_id = ?'
    ).bind(newDate, newConfirmed, recordId).run()

    // Log to audit
    await c.env.DB.prepare(`
      INSERT INTO audit_log (user_id, record_id, field, old_value, new_value, action)
      VALUES (?, ?, ?, ?, ?, 'worksheets_cycle')
    `).bind(userId || null, recordId, 'worksheets', statusRecord?.worksheets_date || '', newDate || '').run()

    return c.json({ success: true, date: newDate, confirmed: newConfirmed })
  } catch (error) {
    console.error('Error cycling worksheets:', error)
    return c.json({ error: 'Failed to cycle worksheets' }, 500)
  }
})

// Update notes
app.patch('/api/records/:id/notes', authMiddleware, async (c) => {
  try {
    const recordId = c.req.param('id')
    const { notes } = await c.req.json()
    const userId = c.get('userId')
    const userRole = c.get('role')

    // Only admin can edit notes
    if (userRole !== 'admin') {
      return c.json({ error: 'Permission denied. Only admin can edit notes.' }, 403)
    }

    await c.env.DB.prepare(
      'UPDATE production_records SET notes = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?'
    ).bind(notes, recordId).run()

    // Log to audit
    await c.env.DB.prepare(`
      INSERT INTO audit_log (user_id, record_id, field, old_value, new_value, action)
      VALUES (?, ?, ?, ?, ?, 'update_notes')
    `).bind(userId || null, recordId, 'notes', '', notes).run()

    return c.json({ success: true })
  } catch (error) {
    console.error('Error updating notes:', error)
    return c.json({ error: 'Failed to update notes' }, 500)
  }
})

// Update problems and error flags
app.patch('/api/records/:id/problems', authMiddleware, async (c) => {
  try {
    const recordId = c.req.param('id')
    const { problems, errorFlags } = await c.req.json()
    const userId = c.get('userId')
    const userRole = c.get('role')

    // User and admin can edit problems
    if (userRole !== 'admin' && userRole !== 'user') {
      return c.json({ error: 'Permission denied. Only admin and user can edit problems.' }, 403)
    }

    // Update problems text
    await c.env.DB.prepare(
      'UPDATE production_records SET problems = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?'
    ).bind(problems, recordId).run()

    // Update error flags
    await c.env.DB.prepare(`
      UPDATE status_checkboxes 
      SET worksheets_error = ?, 
          cutting_error = ?, 
          glazing_error = ?, 
          ready_error = ?, 
          issued_error = ?
      WHERE record_id = ?
    `).bind(
      errorFlags.worksheets ? 1 : 0,
      errorFlags.cutting ? 1 : 0,
      errorFlags.glazing ? 1 : 0,
      errorFlags.ready ? 1 : 0,
      errorFlags.issued ? 1 : 0,
      recordId
    ).run()

    // Log to audit
    await c.env.DB.prepare(`
      INSERT INTO audit_log (user_id, record_id, field, old_value, new_value, action)
      VALUES (?, ?, ?, ?, ?, 'update_problems')
    `).bind(userId || null, recordId, 'problems', '', problems).run()

    return c.json({ success: true })
  } catch (error) {
    console.error('Error updating problems:', error)
    return c.json({ error: 'Failed to update problems' }, 500)
  }
})

// Toggle material confirmed
app.patch('/api/records/:id/material-confirmed', optionalAuthMiddleware, async (c) => {
  try {
    const recordId = c.req.param('id')
    console.log('[MAT1] Toggle request for record:', recordId)
    
    // Get current value
    const current = await c.env.DB.prepare(
      'SELECT material_confirmed FROM status_checkboxes WHERE record_id = ?'
    ).bind(recordId).first()
    
    console.log('[MAT1] Current value:', current?.material_confirmed)
    
    // Toggle value
    const newValue = current?.material_confirmed === 1 ? 0 : 1
    console.log('[MAT1] New value:', newValue)

    await c.env.DB.prepare(
      'UPDATE status_checkboxes SET material_confirmed = ? WHERE record_id = ?'
    ).bind(newValue, recordId).run()

    console.log('[MAT1] Update completed successfully')
    return c.json({ success: true, newValue })
  } catch (error) {
    console.error('[MAT1] Error updating material confirmed:', error)
    return c.json({ error: 'Failed to update material confirmed' }, 500)
  }
})

// Toggle material2 confirmed
app.patch('/api/records/:id/material2-confirmed', optionalAuthMiddleware, async (c) => {
  try {
    const recordId = c.req.param('id')
    console.log('[MAT2] Toggle request for record:', recordId)
    
    // Get current value
    const current = await c.env.DB.prepare(
      'SELECT material2_confirmed FROM status_checkboxes WHERE record_id = ?'
    ).bind(recordId).first()
    
    console.log('[MAT2] Current value:', current?.material2_confirmed)
    
    // Toggle value
    const newValue = current?.material2_confirmed === 1 ? 0 : 1
    console.log('[MAT2] New value:', newValue)

    await c.env.DB.prepare(
      'UPDATE status_checkboxes SET material2_confirmed = ? WHERE record_id = ?'
    ).bind(newValue, recordId).run()

    console.log('[MAT2] Update completed successfully')
    return c.json({ success: true, newValue })
  } catch (error) {
    console.error('[MAT2] Error updating material2 confirmed:', error)
    return c.json({ error: 'Failed to update material2 confirmed' }, 500)
  }
})

// Update price paid status (for invoice tracking)
app.patch('/api/records/:id/price-paid', optionalAuthMiddleware, async (c) => {
  try {
    const recordId = c.req.param('id')
    const { paid } = await c.req.json()

    // You might want to add a 'paid' field to production_records table
    // For now, we'll just return success
    // TODO: Add paid field to schema if needed

    return c.json({ success: true })
  } catch (error) {
    console.error('Error updating price paid:', error)
    return c.json({ error: 'Failed to update price paid' }, 500)
  }
})

// ==================== DEFAULT ROUTE ====================


// ==================== MAIN PAGE - ORIGINAL HTML FROM ARCHIVE ====================  
app.get('/', (c) => {
  return c.html(ORIGINAL_HTML)
})

// Test page for debugging clicks
app.get('/test-click', (c) => {
  return c.html(`<!DOCTYPE html>
<html>
<head>
    <title>Click Test</title>
    <style>
        body { font-family: Arial; padding: 50px; }
        .box { 
            width: 200px; 
            height: 100px; 
            background: #4F46E5; 
            color: white; 
            display: flex; 
            align-items: center; 
            justify-content: center;
            cursor: pointer;
            margin: 20px 0;
        }
        #result { 
            margin-top: 20px; 
            padding: 20px; 
            background: #f0f0f0; 
        }
    </style>
</head>
<body>
    <h1>Click Test Page</h1>
    <div class="box" onclick="handleClick(1)">Click Me (onclick)</div>
    <div class="box" id="box2">Click Me (addEventListener)</div>
    <div id="result">Waiting for click...</div>

    <script>
        // Test 1: inline onclick
        function handleClick(num) {
            document.getElementById('result').innerHTML = '✅ Test ' + num + ': onclick works!';
        }

        // Test 2: addEventListener
        document.addEventListener('DOMContentLoaded', () => {
            document.getElementById('box2').addEventListener('click', () => {
                document.getElementById('result').innerHTML = '✅ Test 2: addEventListener works!';
            });
            console.log('✅ DOMContentLoaded fired and event listener attached');
        });
    </script>
</body>
</html>`)
})


export default app
