package com.companycam.clone.data.repository

import com.companycam.clone.data.api.AIAnalysisApiService
import com.companycam.clone.data.database.AIAnalysisDao
import com.companycam.clone.data.models.AIAnalysis
import com.companycam.clone.data.models.AnalysisType
import com.companycam.clone.data.models.DailyLog
import com.companycam.clone.data.models.DefectDetectionResult
import com.companycam.clone.data.models.GeometryEstimationResult
import com.companycam.clone.data.models.MaterialDetectionResult
import com.companycam.clone.data.models.PermitOcrResult
import com.companycam.clone.data.models.WalkthroughTranscript
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import java.io.File
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class AIRepository @Inject constructor(
    private val aiApiService: AIAnalysisApiService,
    private val analysisDao: AIAnalysisDao
) {

    suspend fun analyzeDefects(photoPath: String): Result<DefectDetectionResult> {
        return try {
            val file = File(photoPath)
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("image", file.name,
                    RequestBody.create("image/jpeg".toMediaTypeOrNull(), file)
                )
                .build()

            val response = aiApiService.analyzeDefects(requestBody)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun detectMaterials(photoPath: String): Result<MaterialDetectionResult> {
        return try {
            val file = File(photoPath)
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("image", file.name,
                    RequestBody.create("image/jpeg".toMediaTypeOrNull(), file)
                )
                .build()

            val response = aiApiService.detectMaterials(requestBody)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun estimateGeometry(photoPath: String): Result<GeometryEstimationResult> {
        return try {
            val file = File(photoPath)
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("image", file.name,
                    RequestBody.create("image/jpeg".toMediaTypeOrNull(), file)
                )
                .build()

            val response = aiApiService.estimateGeometry(requestBody)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun scanPermit(photoPath: String): Result<PermitOcrResult> {
        return try {
            val file = File(photoPath)
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("image", file.name,
                    RequestBody.create("image/jpeg".toMediaTypeOrNull(), file)
                )
                .build()

            val response = aiApiService.scanPermit(requestBody)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun transcribeWalkthrough(audioPath: String): Result<WalkthroughTranscript> {
        return try {
            val file = File(audioPath)
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("audio", file.name,
                    RequestBody.create("audio/mp4".toMediaTypeOrNull(), file)
                )
                .addFormDataPart("language", "en")
                .build()

            val response = aiApiService.transcribeAudio(requestBody)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun generateDailyLog(projectId: Long, transcriptId: String): Result<DailyLog> {
        return try {
            val response = aiApiService.generateDailyLog(projectId, transcriptId)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun saveAnalysis(analysis: AIAnalysis): Long {
        return analysisDao.insertAnalysis(analysis)
    }

    fun getAnalysesForPhoto(photoId: Long): Flow<List<AIAnalysis>> {
        return analysisDao.getAnalysisForPhoto(photoId)
    }
}
package com.companycam.clone.data.api

import com.companycam.clone.data.models.DailyLog
import com.companycam.clone.data.models.DefectDetectionResult
import com.companycam.clone.data.models.GeometryEstimationResult
import com.companycam.clone.data.models.MaterialDetectionResult
import com.companycam.clone.data.models.PermitOcrResult
import com.companycam.clone.data.models.WalkthroughTranscript
import okhttp3.MultipartBody
import retrofit2.http.Body
import retrofit2.http.POST
import retrofit2.http.Path

interface AIAnalysisApiService {

    @POST("ai/analyze-defects")
    suspend fun analyzeDefects(@Body request: MultipartBody): DefectDetectionResult

    @POST("ai/detect-materials")
    suspend fun detectMaterials(@Body request: MultipartBody): MaterialDetectionResult

    @POST("ai/estimate-geometry")
    suspend fun estimateGeometry(@Body request: MultipartBody): GeometryEstimationResult

    @POST("ai/scan-permit")
    suspend fun scanPermit(@Body request: MultipartBody): PermitOcrResult

    @POST("ai/transcribe")
    suspend fun transcribeAudio(@Body request: MultipartBody): WalkthroughTranscript

    @POST("ai/daily-log")
    suspend fun generateDailyLog(
        @Body request: DailyLogRequest
    ): DailyLog
}

data class DailyLogRequest(
    val projectId: Long,
    val transcriptId: String,
    val includePhotos: Boolean = true
)


**Analyzing the Discrepancy**

I've pinpointed the error! It's in `AIRepository.kt:116`, specifically the `generateDailyLog` call. The issue is a mismatch in arguments. The repository is calling the service with `projectId` and `transcriptId`, but the service's `generateDailyLog` expects a `DailyLogRequest` object. I am now working on formulating the correct request object.

exec

cat > android/app/src/main/java/com/companycam/clone/data/repository/AIRepository.kt <<EOF
package com.companycam.clone.data.repository

import com.companycam.clone.data.api.AIAnalysisApiService
import com.companycam.clone.data.api.DailyLogRequest
import com.companycam.clone.data.database.AIAnalysisDao
import com.companycam.clone.data.models.AIAnalysis
import com.companycam.clone.data.models.AnalysisType
import com.companycam.clone.data.models.DailyLog
import com.companycam.clone.data.models.DefectDetectionResult
import com.companycam.clone.data.models.GeometryEstimationResult
import com.companycam.clone.data.models.MaterialDetectionResult
import com.companycam.clone.data.models.PermitOcrResult
import com.companycam.clone.data.models.WalkthroughTranscript
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import java.io.File
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class AIRepository @Inject constructor(
    private val aiApiService: AIAnalysisApiService,
    private val analysisDao: AIAnalysisDao
) {

    suspend fun analyzeDefects(photoPath: String): Result<DefectDetectionResult> {
        return try {
            val file = File(photoPath)
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("image", file.name,
                    RequestBody.create("image/jpeg".toMediaTypeOrNull(), file)
                )
                .build()

            val response = aiApiService.analyzeDefects(requestBody)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun detectMaterials(photoPath: String): Result<MaterialDetectionResult> {
        return try {
            val file = File(photoPath)
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("image", file.name,
                    RequestBody.create("image/jpeg".toMediaTypeOrNull(), file)
                )
                .build()

            val response = aiApiService.detectMaterials(requestBody)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun estimateGeometry(photoPath: String): Result<GeometryEstimationResult> {
        return try {
            val file = File(photoPath)
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("image", file.name,
                    RequestBody.create("image/jpeg".toMediaTypeOrNull(), file)
                )
                .build()

            val response = aiApiService.estimateGeometry(requestBody)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun scanPermit(photoPath: String): Result<PermitOcrResult> {
        return try {
            val file = File(photoPath)
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("image", file.name,
                    RequestBody.create("image/jpeg".toMediaTypeOrNull(), file)
                )
                .build()

            val response = aiApiService.scanPermit(requestBody)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun transcribeWalkthrough(audioPath: String): Result<WalkthroughTranscript> {
        return try {
            val file = File(audioPath)
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("audio", file.name,
                    RequestBody.create("audio/mp4".toMediaTypeOrNull(), file)
                )
                .addFormDataPart("language", "en")
                .build()

            val response = aiApiService.transcribeAudio(requestBody)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun generateDailyLog(projectId: Long, transcriptId: String): Result<DailyLog> {
        return try {
            val request = DailyLogRequest(projectId, transcriptId)
            val response = aiApiService.generateDailyLog(request)
            Result.success(response)
        } catch (e: Exception) {
            Result.failure(e)
        }
    }

    suspend fun saveAnalysis(analysis: AIAnalysis): Long {
        return analysisDao.insertAnalysis(analysis)
    }

    fun getAnalysesForPhoto(photoId: Long): Flow<List<AIAnalysis>> {
        return analysisDao.getAnalysisForPhoto(photoId)
    }
}
EOF


(no output)


Command still running (session briny-rook, pid 971287). Use process (list/poll/log/write/kill/clear/remove) for follow-up.


To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.4/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation.
Daemon will be stopped at the end of the build
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :app:checkKotlinGradlePluginConfigurationErrors


To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.4/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation.
Daemon will be stopped at the end of the build
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :app:checkKotlinGradlePluginConfigurationErrors
> Task :app:checkDebugAarMetadata UP-TO-DATE
> Task :app:generateDebugResValues UP-TO-DATE
> Task :app:mapDebugSourceSetPaths UP-TO-DATE
> Task :app:generateDebugResources UP-TO-DATE
> Task :app:mergeDebugResources UP-TO-DATE
> Task :app:packageDebugResources UP-TO-DATE
> Task :app:parseDebugLocalResources UP-TO-DATE
> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :app:extractDeepLinksDebug UP-TO-DATE
> Task :app:processDebugMainManifest UP-TO-DATE
> Task :app:processDebugManifest UP-TO-DATE
> Task :app:processDebugManifestForPackage UP-TO-DATE
> Task :app:processDebugResources UP-TO-DATE
> Task :app:javaPreCompileDebug UP-TO-DATE
> Task :app:mergeDebugShaders UP-TO-DATE
> Task :app:compileDebugShaders NO-SOURCE
> Task :app:generateDebugAssets UP-TO-DATE
> Task :app:mergeDebugAssets UP-TO-DATE
> Task :app:compressDebugAssets UP-TO-DATE
> Task :app:desugarDebugFileDependencies UP-TO-DATE
> Task :app:checkDebugDuplicateClasses UP-TO-DATE
> Task :app:mergeExtDexDebug UP-TO-DATE
> Task :app:mergeLibDexDebug UP-TO-DATE
> Task :app:mergeDebugJniLibFolders UP-TO-DATE
> Task :app:mergeDebugNativeLibs UP-TO-DATE
> Task :app:stripDebugDebugSymbols UP-TO-DATE
> Task :app:validateSigningDebug UP-TO-DATE
> Task :app:writeDebugAppMetadata UP-TO-DATE
> Task :app:writeDebugSigningConfigVersions UP-TO-DATE
> Task :app:kspDebugKotlin
> Task :app:kaptGenerateStubsDebugKotlin


To honour the JVM settings for this build a single-use Daemon process will be forked. For more on this, please refer to https://docs.gradle.org/8.4/userguide/gradle_daemon.html#sec:disabling_the_daemon in the Gradle documentation.
Daemon will be stopped at the end of the build
> Task :app:preBuild UP-TO-DATE
> Task :app:preDebugBuild UP-TO-DATE
> Task :app:mergeDebugNativeDebugMetadata NO-SOURCE
> Task :app:checkKotlinGradlePluginConfigurationErrors
> Task :app:checkDebugAarMetadata UP-TO-DATE
> Task :app:generateDebugResValues UP-TO-DATE
> Task :app:mapDebugSourceSetPaths UP-TO-DATE
> Task :app:generateDebugResources UP-TO-DATE
> Task :app:mergeDebugResources UP-TO-DATE
> Task :app:packageDebugResources UP-TO-DATE
> Task :app:parseDebugLocalResources UP-TO-DATE
> Task :app:createDebugCompatibleScreenManifests UP-TO-DATE
> Task :app:extractDeepLinksDebug UP-TO-DATE
> Task :app:processDebugMainManifest UP-TO-DATE
> Task :app:processDebugManifest UP-TO-DATE
> Task :app:processDebugManifestForPackage UP-TO-DATE
> Task :app:processDebugResources UP-TO-DATE
> Task :app:javaPreCompileDebug UP-TO-DATE
> Task :app:mergeDebugShaders UP-TO-DATE
> Task :app:compileDebugShaders NO-SOURCE
> Task :app:generateDebugAssets UP-TO-DATE
> Task :app:mergeDebugAssets UP-TO-DATE
> Task :app:compressDebugAssets UP-TO-DATE
> Task :app:desugarDebugFileDependencies UP-TO-DATE
> Task :app:checkDebugDuplicateClasses UP-TO-DATE
> Task :app:mergeExtDexDebug UP-TO-DATE
> Task :app:mergeLibDexDebug UP-TO-DATE
> Task :app:mergeDebugJniLibFolders UP-TO-DATE
> Task :app:mergeDebugNativeLibs UP-TO-DATE
> Task :app:stripDebugDebugSymbols UP-TO-DATE
> Task :app:validateSigningDebug UP-TO-DATE
> Task :app:writeDebugAppMetadata UP-TO-DATE
> Task :app:writeDebugSigningConfigVersions UP-TO-DATE
> Task :app:kspDebugKotlin
> Task :app:kaptGenerateStubsDebugKotlin

> Task :app:kaptDebugKotlin
warning: The following options were not recognized by any processor: '[room.schemaLocation, kapt.kotlin.generated]'

> Task :app:compileDebugKotlin FAILED
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/PermitScannerScreen.kt:99:47 Unresolved reference: DocumentScanner
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/PermitScannerScreen.kt:165:27 Unresolved reference: CameraAlt
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/camera/CameraScreen.kt:74:56 Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val Icons.Filled.ArrowBack: ImageVector defined in androidx.compose.material.icons.filled
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/camera/CameraScreen.kt:197:39 Type mismatch: inferred type is FlashMode but Int was expected
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/camera/CameraScreen.kt:215:28 Unresolved reference: getMainExecutor
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/camera/CameraViewModel.kt:47:21 Type mismatch: inferred type is CoroutineContext but Executor was expected
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/camera/CameraViewModel.kt:86:70 Unresolved reference: Exception
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/media/PhotoDetailScreen.kt:23:31 Unresolved reference: pager
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/media/PhotoDetailScreen.kt:24:31 Unresolved reference: pager
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/media/PhotoDetailScreen.kt:177:21 Cannot find a parameter with this name: verticalArrangement
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/media/PhotoDetailScreen.kt:213:67 Unresolved reference: Locale
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/media/PhotoEditorScreen.kt:200:45 Unresolved reference: pow
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/media/PhotoEditorScreen.kt:201:45 Unresolved reference: pow
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/media/PhotoEditorScreen.kt:203:65 Type mismatch: inferred type is Double but Float was expected
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/media/PhotoEditorScreen.kt:366:34 Unresolved reference: luminance
e: file:///home/crogers2287/company-cam-clone/android/app/src/main/java/com/companycam/clone/ui/screens/projects/ProjectDetailScreen.kt:56:56 Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val Icons.Filled.ArrowBack: ImageVector defined in androidx.compose.material.icons.filled

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileDebugKotlin'.
> A failure occurred while executing org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers$GradleKotlinCompilerWorkAction
   > Compilation error. See log for more details

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 24s
32 actionable tasks: 5 executed, 27 up-to-date


**Addressing UI Errors**

Okay, I've cleared the data layer; no more issues there! Now, it's just the UI and Camera. Specifically, I'm getting an error in `PermitScannerScreen.kt` regarding an unresolved `DocumentScanner`. Looks like I need to comment this out, likely a missing class. It seems like the only remaining barrier.

**Resolving Compilation Issues**

I'm now diving into the compilation errors. The `ArrowBack` icon and `FlashMode` type mismatch are easy fixes in `CameraScreen.kt`. I'm also addressing the `getMainExecutor` issue in `CameraScreen.kt` and `CameraViewModel.kt`, and have resolved the unresolved imports. I'm importing `kotlin.math.pow` in `PhotoEditorScreen.kt` for `pow` and `androidx.compose.ui.graphics.luminance` for luminance. I still need to resolve the pager issue in `PhotoDetailScreen.kt`, and I've started checking the code for remaining issues.


package com.companycam.clone.ui.screens.camera

import android.Manifest
import android.content.Context
import android.net.Uri
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.*
import androidx.camera.view.PreviewView
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import com.companycam.clone.util.ExifUtils
import com.companycam.clone.util.LocationManager
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
import javax.inject.Inject

@OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class)
@Composable
fun CameraScreen(
    navController: NavHostController,
    projectId: Long? = null,
    viewModel: CameraViewModel = hiltViewModel()
) {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current

    var lensFacing by remember { mutableStateOf(CameraSelector.LENS_FACING_BACK) }
    var flashMode by remember { mutableStateOf(FlashMode.OFF) }
    var isRecording by remember { mutableStateOf(false) }

    val permissionsState = rememberMultiplePermissionsState(
        permissions = listOf(
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.ACCESS_FINE_LOCATION
        )
    )

    val cameraState by viewModel.cameraState.collectAsState()

    LaunchedEffect(Unit) {
        if (!permissionsState.allPermissionsGranted) {
            permissionsState.launchMultiplePermissionRequest()
        }
    }

    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text(getProjectTitle(projectId)) },
                navigationIcon = {
                    IconButton(onClick = { navController.navigateUp() }) {
                        Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
                    }
                },
                actions = {
                    // Flash toggle
                    IconButton(
                        onClick = {
                            flashMode = when (flashMode) {
                                FlashMode.ON -> FlashMode.OFF
                                FlashMode.OFF -> FlashMode.AUTO
                                FlashMode.AUTO -> FlashMode.ON
                            }
                        }
                    ) {
                        Icon(
                            when (flashMode) {
                                FlashMode.ON -> Icons.Default.FlashOn
                                FlashMode.OFF -> Icons.Default.FlashOff
                                FlashMode.AUTO -> Icons.Default.FlashAuto
                            },
                            contentDescription = "Flash"
                        )
                    }

                    // More options
                    IconButton(onClick = { /* Show menu */ }) {
                        Icon(Icons.Default.MoreVert, contentDescription = "More")
                    }
                }
            )
        }
    ) { paddingValues ->
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
        ) {
            if (permissionsState.allPermissionsGranted) {
                CameraPreview(
                    onImageCaptured = { imageCapture ->
                        viewModel.capturePhoto(
                            context = context,
                            imageCapture = imageCapture,
                            projectId = projectId,
                            onResult = { photoId ->
                                navController.navigate("photos/$photoId/edit")
                            }
                        )
                    },
                    onVideoRecording = { videoCapture, isStarting ->
                        // Handle video recording
                    },
                    lensFacing = lensFacing,
                    flashMode = flashMode,
                    modifier = Modifier.fillMaxSize()
                )

                // Camera controls overlay
                CameraControls(
                    onSwitchCamera = {
                        lensFacing = if (lensFacing == CameraSelector.LENS_FACING_BACK) {
                            CameraSelector.LENS_FACING_FRONT
                        } else {
                            CameraSelector.LENS_FACING_BACK
                        }
                    },
                    onCapturePhoto = {
                        viewModel.triggerCapture()
                    },
                    isRecording = isRecording,
                    modifier = Modifier
                        .fillMaxWidth()
                        .align(Alignment.BottomCenter)
                        .padding(24.dp)
                )
            } else {
                PermissionRequestContent(
                    onRequestPermission = {
                        permissionsState.launchMultiplePermissionRequest()
                    },
                    modifier = Modifier.align(Alignment.Center)
                )
            }
        }
    }
}

@Composable
fun CameraPreview(
    onImageCaptured: (ImageCapture) -> Unit,
    onVideoRecording: (VideoCapture<Recorder>, Boolean) -> Unit,
    lensFacing: Int,
    flashMode: FlashMode,
    modifier: Modifier = Modifier
) {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current

    var previewView by remember { mutableStateOf<PreviewView?>(null) }
    var imageCapture by remember { mutableStateOf<ImageCapture?>(null) }

    // Trigger capture when requested
    LaunchedEffect(imageCapture) {
        // This will be triggered by parent via a callback
    }

    AndroidView(
        factory = { ctx ->
            PreviewView(ctx).apply {
                previewView = this

                val cameraProviderFuture = ProcessCameraProvider.getInstance(ctx)
                cameraProviderFuture.addListener({
                    val cameraProvider = cameraProviderFuture.get()

                    val preview = Preview.Builder()
                        .build()
                        .also {
                            it.setSurfaceProvider(surfaceProvider)
                        }

                    imageCapture = ImageCapture.Builder()
                        .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                        .setFlashMode(flashMode)
                        .build()

                    val cameraSelector = CameraSelector.Builder()
                        .requireLensFacing(lensFacing)
                        .build()

                    try {
                        cameraProvider.unbindAll()
                        cameraProvider.bindToLifecycle(
                            lifecycleOwner,
                            cameraSelector,
                            preview,
                            imageCapture
                        )
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }, Context.getMainExecutor(ctx))
            }
        },
        modifier = modifier
    )

    // Store imageCapture callback
    LaunchedEffect(imageCapture) {
        imageCapture?.let { imgCap ->
            // Store for parent to trigger
        }
    }
}

@Composable
fun CameraControls(
    onSwitchCamera: () -> Unit,
    onCapturePhoto: () -> Unit,
    isRecording: Boolean,
    modifier: Modifier = Modifier
) {
    Row(
        modifier = modifier,
        horizontalArrangement = Arrangement.SpaceAround,
        verticalAlignment = Alignment.CenterVertically
    ) {
        // Gallery thumbnail
        IconButton(
            onClick = { /* Open gallery */ },
            modifier = Modifier
                .size(56.dp)
                .clip(RoundedCornerShape(8.dp))
        ) {
            Icon(
                Icons.Default.PhotoLibrary,
                contentDescription = "Gallery",
                modifier = Modifier.size(32.dp)
            )
        }

        // Capture button
        IconButton(
            onClick = onCapturePhoto,
            modifier = Modifier.size(80.dp)
        ) {
            Box(
                modifier = Modifier
                    .size(72.dp)
                    .background(Color.White, CircleShape)
                    .padding(4.dp)
            ) {
                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .background(Color.Black, CircleShape)
                )
            }
        }

        // Switch camera / Video toggle
        IconButton(onClick = onSwitchCamera) {
            Icon(
                Icons.Default.FlipCameraIos,
                contentDescription = "Switch Camera",
                modifier = Modifier.size(32.dp)
            )
        }
    }
}

@Composable
fun PermissionRequestContent(
    onRequestPermission: () -> Unit,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier.padding(32.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Icon(
            Icons.Default.CameraAlt,
            contentDescription = null,
            modifier = Modifier.size(64.dp),
            tint = MaterialTheme.colorScheme.primary
        )
        Spacer(modifier = Modifier.height(16.dp))
        Text(
            text = "Camera Permission Required",
            style = MaterialTheme.typography.titleLarge,
            fontWeight = FontWeight.Bold
        )
        Spacer(modifier = Modifier.height(8.dp))
        Text(
            text = "CompanyCam Clone needs camera, location, and microphone permissions to capture photos with metadata.",
            style = MaterialTheme.typography.bodyMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant
        )
        Spacer(modifier = Modifier.height(24.dp))
        Button(onClick = onRequestPermission) {
            Text("Grant Permissions")
        }
    }
}

fun getProjectTitle(projectId: Long?): String {
    return if (projectId != null) "Capture Photo" else "Select Project"
}

enum class FlashMode {
    ON,
    OFF,
    AUTO
}
package com.companycam.clone.ui.screens.camera

import android.content.Context
import android.net.Uri
import androidx.camera.core.ImageCapture
import androidx.lifecycle.viewModelScope
import com.companycam.clone.data.repository.PhotoRepository
import com.companycam.clone.util.ExifUtils
import com.companycam.clone.util.LocationManager
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
import javax.inject.Inject

@HiltViewModel
class CameraViewModel @Inject constructor(
    private val photoRepository: PhotoRepository,
    private val locationManager: LocationManager
) : androidx.lifecycle.ViewModel() {

    private val _cameraState = MutableStateFlow(CameraState())
    val cameraState: StateFlow<CameraState> = _cameraState.asStateFlow()

    private var onCaptureResult: ((Long) -> Unit)? = null

    fun capturePhoto(
        context: Context,
        imageCapture: ImageCapture,
        projectId: Long?,
        onResult: (Long) -> Unit
    ) {
        onCaptureResult = onResult
        viewModelScope.launch {
            try {
                val location = locationManager.getCurrentLocation()
                val photoFile = photoRepository.createImageFile()

                val outputFileOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

                imageCapture.takePicture(
                    outputFileOptions,
                    viewModelScope.coroutineContext + kotlinx.coroutines.Dispatchers.Main,
                    object : ImageCapture.OnImageSavedCallback {
                        override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                            viewModelScope.launch {
                                // Stamp EXIF metadata
                                ExifUtils.stampMetadata(
                                    file = photoFile,
                                    location = location,
                                    userId = "user_123", // Get from auth
                                    userName = "Current User"
                                )

                                // Create watermarked version
                                val watermarkFile = File(photoFile.parent, "watermarked_${photoFile.name}")
                                ExifUtils.addWatermark(
                                    sourceFile = photoFile,
                                    outputFile = watermarkFile,
                                    userName = "Current User",
                                    location = location,
                                    context = context
                                )

                                // Save to database
                                val savedProjectId = projectId ?: 1L // Default to first project
                                val photoId = photoRepository.savePhoto(
                                    projectId = savedProjectId,
                                    localPath = watermarkFile.absolutePath,
                                    thumbnailPath = null,
                                    latitude = location?.latitude,
                                    longitude = location?.longitude,
                                    altitude = location?.altitude,
                                    capturedBy = "Current User",
                                    capturedByUserId = "user_123"
                                )

                                onCaptureResult?.invoke(photoId)
                            }
                        }

                        override fun onError(exception: ImageCapture.Exception) {
                            exception.printStackTrace()
                        }
                    }
                )
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    fun triggerCapture() {
        _cameraState.value = _cameraState.value.copy(
            shouldCapture = _cameraState.value.shouldCapture + 1
        )
    }
}

data class CameraState(
    val isProcessing: Boolean = false,
    val shouldCapture: Int = 0
)
package com.companycam.clone.ui.screens.media

import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTransformGestures
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import coil.compose.AsyncImage
import com.google.accompanist.pager.HorizontalPager
import com.google.accompanist.pager.rememberPagerState

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PhotoDetailScreen(
    photoId: Long,
    navController: NavHostController,
    viewModel: PhotoDetailViewModel = hiltViewModel()
) {
    val photo by viewModel.photo.collectAsState()
    val annotations by viewModel.annotations.collectAsState()

    Scaffold(
        topBar = {
            TopAppBar(
                title = { },
                navigationIcon = {
                    IconButton(onClick = { navController.navigateUp() }) {
                        Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
                    }
                },
                actions = {
                    IconButton(onClick = { navController.navigate("photos/$photoId/edit") }) {
                        Icon(Icons.Default.Edit, contentDescription = "Edit")
                    }
                    IconButton(onClick = { viewModel.toggleAIAnalysis() }) {
                        Icon(Icons.Default.AutoAwesome, contentDescription = "AI Analysis")
                    }
                    IconButton(onClick = { /* Share */ }) {
                        Icon(Icons.Default.Share, contentDescription = "Share")
                    }
                    IconButton(onClick = { /* Delete */ }) {
                        Icon(Icons.Default.Delete, contentDescription = "Delete")
                    }
                },
                colors = TopAppBarDefaults.topAppBarColors(
                    containerColor = Color.Transparent
                )
            )
        }
    ) { paddingValues ->
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
        ) {
            photo?.let { currentPhoto ->
                ZoomableImage(
                    imageUrl = currentPhoto.localPath,
                    modifier = Modifier.fillMaxSize()
                )

                // Photo info overlay at bottom
                PhotoInfoOverlay(
                    photo = currentPhoto,
                    modifier = Modifier
                        .align(Alignment.BottomCenter)
                        .fillMaxWidth()
                )
            }
        }
    }
}

@Composable
fun ZoomableImage(
    imageUrl: String,
    modifier: Modifier = Modifier
) {
    var scale by remember { mutableStateOf(1f) }
    var offset by remember { mutableStateOf(Offset.Zero) }

    AsyncImage(
        model = imageUrl,
        contentDescription = null,
        modifier = modifier
            .pointerInput(Unit) {
                detectTransformGestures { _, _, zoom, _ ->
                    scale = (scale * zoom).coerceIn(0.5f, 4f)
                }
            }
            .graphicsLayer {
                scaleX = scale
                scaleY = scale
                translationX = offset.x
                translationY = offset.y
            },
        contentScale = ContentScale.Fit
    )
}

@Composable
fun PhotoInfoOverlay(
    photo: com.companycam.clone.data.models.Photo,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier
            .background(Color.Black.copy(alpha = 0.7f))
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Column {
                Text(
                    text = formatTimestamp(photo.capturedAt),
                    style = MaterialTheme.typography.bodyMedium,
                    color = Color.White
                )
                Text(
                    text = "By ${photo.capturedBy}",
                    style = MaterialTheme.typography.bodySmall,
                    color = Color.White.copy(alpha = 0.7f)
                )
            }

            if (photo.latitude != null && photo.longitude != null) {
                Surface(
                    color = Color.White.copy(alpha = 0.2f),
                    shape = RoundedCornerShape(8.dp)
                ) {
                    Row(
                        modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Icon(
                            Icons.Default.LocationOn,
                            contentDescription = null,
                            tint = Color.White,
                            modifier = Modifier.size(16.dp)
                        )
                        Spacer(modifier = Modifier.width(4.dp))
                        Text(
                            text = "%.4f, %.4f".format(photo.latitude, photo.longitude),
                            style = MaterialTheme.typography.bodySmall,
                            color = Color.White
                        )
                    }
                }
            }
        }

        // AI Analysis badge
        if (!photo.aiAnalysis.isNullOrBlank()) {
            Surface(
                color = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.8f),
                shape = RoundedCornerShape(8.dp)
            ) {
                Row(
                    modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
                    verticalArrangement = Arrangement.Center
                ) {
                    Icon(
                        Icons.Default.AutoAwesome,
                        contentDescription = null,
                        modifier = Modifier.size(16.dp),
                        tint = Color.White
                    )
                    Spacer(modifier = Modifier.width(8.dp))
                    Text(
                        text = "AI Analysis Available",
                        style = MaterialTheme.typography.labelMedium,
                        color = Color.White
                    )
                }
            }
        }

        // Before/After indicator
        if (photo.isBefore) {
            Surface(
                color = Color(0xFFFF6D00).copy(alpha = 0.8f),
                shape = RoundedCornerShape(8.dp)
            ) {
                Text(
                    text = "BEFORE PHOTO",
                    modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
                    style = MaterialTheme.typography.labelMedium,
                    color = Color.White
                )
            }
        }
    }
}

fun formatTimestamp(timestamp: Long): String {
    val sdf = java.text.SimpleDateFormat("MMM dd, yyyy • h:mm a", Locale.US)
    return sdf.format(java.util.Date(timestamp))
}
package com.companycam.clone.ui.screens.media

import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path as ComposePath
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import coil.compose.AsyncImage

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PhotoEditorScreen(
    photoId: Long,
    navController: NavHostController,
    viewModel: PhotoEditorViewModel = hiltViewModel()
) {
    val photo by viewModel.photo.collectAsState()
    var selectedTool by remember { mutableStateOf(DrawingTool.PEN) }
    var selectedColor by remember { mutableStateOf(Color.Red) }
    var strokeWidth by remember { mutableStateOf(5f) }

    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text("Edit Photo") },
                navigationIcon = {
                    IconButton(onClick = { navController.navigateUp() }) {
                        Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
                    }
                },
                actions = {
                    IconButton(onClick = { viewModel.undo() }) {
                        Icon(Icons.Default.Undo, contentDescription = "Undo")
                    }
                    IconButton(onClick = { viewModel.redo() }) {
                        Icon(Icons.Default.Redo, contentDescription = "Redo")
                    }
                    IconButton(onClick = { viewModel.saveEdits { navController.navigateUp() } }) {
                        Icon(Icons.Default.Check, contentDescription = "Save")
                    }
                }
            )
        },
        bottomBar = {
            EditorToolbar(
                selectedTool = selectedTool,
                selectedColor = selectedColor,
                strokeWidth = strokeWidth,
                onToolSelected = { selectedTool = it },
                onColorSelected = { selectedColor = it },
                onStrokeWidthChanged = { strokeWidth = it },
                modifier = Modifier.fillMaxWidth()
            )
        }
    ) { paddingValues ->
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
        ) {
            photo?.let { currentPhoto ->
                DrawingCanvas(
                    imageUrl = currentPhoto.localPath,
                    tool = selectedTool,
                    color = selectedColor,
                    strokeWidth = strokeWidth,
                    onPathComplete = { path, bounds ->
                        viewModel.addAnnotation(path, bounds, selectedTool, selectedColor)
                    },
                    modifier = Modifier.fillMaxSize()
                )
            }
        }
    }
}

@Composable
fun DrawingCanvas(
    imageUrl: String,
    tool: DrawingTool,
    color: Color,
    strokeWidth: Float,
    onPathComplete: (List<Offset>, Pair<Offset, Offset>?) -> Unit,
    modifier: Modifier = Modifier
) {
    var currentPath by remember { mutableStateOf<List<Offset>>(emptyList()) }
    var startPoint by remember { mutableStateOf<Offset?>(null) }
    var currentPoint by remember { mutableStateOf<Offset?>(null) }

    Box(modifier = modifier) {
        // Background image
        AsyncImage(
            model = imageUrl,
            contentDescription = null,
            modifier = Modifier.fillMaxSize(),
            contentScale = androidx.compose.ui.layout.ContentScale.Fit
        )

        // Drawing surface
        Canvas(
            modifier = Modifier
                .fillMaxSize()
                .pointerInput(Unit) {
                    detectDragGestures(
                        onDragStart = { offset ->
                            when (tool) {
                                DrawingTool.PEN, DrawingTool.ARROW -> {
                                    currentPath = listOf(offset)
                                }
                                DrawingTool.CIRCLE, DrawingTool.RECTANGLE -> {
                                    startPoint = offset
                                    currentPoint = offset
                                }
                                DrawingTool.TEXT -> {
                                    // Show text input dialog at position
                                }
                                else -> {}
                            }
                        },
                        onDrag = { change, dragAmount ->
                            change.consume()
                            when (tool) {
                                DrawingTool.PEN, DrawingTool.ARROW -> {
                                    currentPath = currentPath + change.position
                                }
                                DrawingTool.CIRCLE, DrawingTool.RECTANGLE -> {
                                    currentPoint = change.position
                                }
                                else -> {}
                            }
                        },
                        onDragEnd = {
                            when (tool) {
                                DrawingTool.PEN, DrawingTool.ARROW -> {
                                    onPathComplete(currentPath, null)
                                }
                                DrawingTool.CIRCLE, DrawingTool.RECTANGLE -> {
                                    startPoint?.let { start ->
                                        onPathComplete(emptyList(), start to (currentPoint ?: start))
                                    }
                                }
                                else -> {}
                            }
                            currentPath = emptyList()
                            startPoint = null
                            currentPoint = null
                        }
                    )
                }
        ) {
            // Draw current path/shape
            val canvas = drawContext.canvas.nativeCanvas
            val paint = Paint().apply {
                this.color = android.graphics.Color.parseColor(color.toString().substringAfter("0x"))
                style = Paint.Style.STROKE
                this.strokeWidth = strokeWidth
                isAntiAlias = true
            }

            when (tool) {
                DrawingTool.PEN -> {
                    if (currentPath.size >= 2) {
                        val path = Path()
                        path.moveTo(currentPath[0].x, currentPath[0].y)
                        currentPath.forEach { path.lineTo(it.x, it.y) }
                        canvas.drawPath(path, paint)
                    }
                }
                DrawingTool.ARROW -> {
                    if (currentPath.size >= 2) {
                        val start = currentPath.first()
                        val end = currentPath.last()
                        drawArrow(canvas, paint, start, end)
                    }
                }
                DrawingTool.CIRCLE -> {
                    startPoint?.let { start ->
                        currentPoint?.let { end ->
                            val radius = kotlin.math.sqrt(
                                kotlin.math.pow(end.x - start.x, 2f) +
                                kotlin.math.pow(end.y - start.y, 2f)
                            )
                            canvas.drawCircle(start.x, start.y, radius, paint)
                        }
                    }
                }
                DrawingTool.RECTANGLE -> {
                    startPoint?.let { start ->
                        currentPoint?.let { end ->
                            canvas.drawRect(
                                start.x, start.y, end.x, end.y, paint
                            )
                        }
                    }
                }
                else -> {}
            }
        }
    }
}

fun drawArrow(canvas: android.graphics.Canvas, paint: Paint, start: Offset, end: Offset) {
    val path = Path().apply {
        moveTo(start.x, start.y)
        lineTo(end.x, end.y)
    }
    canvas.drawPath(path, paint)

    // Draw arrow head
    val angle = kotlin.math.atan2(end.y - start.y, end.x - start.x)
    val arrowLength = 20f

    val arrowPath = Path().apply {
        moveTo(end.x, end.y)
        lineTo(
            end.x - arrowLength * kotlin.math.cos(angle - kotlin.math.PI / 6).toFloat(),
            end.y - arrowLength * kotlin.math.sin(angle - kotlin.math.PI / 6).toFloat()
        )
        moveTo(end.x, end.y)
        lineTo(
            end.x - arrowLength * kotlin.math.cos(angle + kotlin.math.PI / 6).toFloat(),
            end.y - arrowLength * kotlin.math.sin(angle + kotlin.math.PI / 6).toFloat()
        )
    }
    canvas.drawPath(arrowPath, paint)
}

@Composable
fun EditorToolbar(
    selectedTool: DrawingTool,
    selectedColor: Color,
    strokeWidth: Float,
    onToolSelected: (DrawingTool) -> Unit,
    onColorSelected: (Color) -> Unit,
    onStrokeWidthChanged: (Float) -> Unit,
    modifier: Modifier = Modifier
) {
    Surface(
        modifier = modifier,
        tonalElevation = 3.dp
    ) {
        Column(
            modifier = Modifier.padding(8.dp),
            verticalArrangement = Arrangement.spacedBy(8.dp)
        ) {
            // Tools row
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceEvenly
            ) {
                DrawingTool.values().forEach { tool ->
                    ToolButton(
                        tool = tool,
                        isSelected = selectedTool == tool,
                        onClick = { onToolSelected(tool) }
                    )
                }
            }

            // Color row
            Row(
                modifier = Modifier.fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceEvenly
            ) {
                listOf(Color.Red, Color.Blue, Color.Green, Color.Yellow, Color.White, Color.Black).forEach { color ->
                    ColorButton(
                        color = color,
                        isSelected = selectedColor == color,
                        onClick = { onColorSelected(color) }
                    )
                }
            }

            // Stroke width slider
            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically
            ) {
                Text("Size:", style = MaterialTheme.typography.bodySmall)
                Slider(
                    value = strokeWidth,
                    onValueChange = onStrokeWidthChanged,
                    valueRange = 1f..20f,
                    modifier = Modifier.weight(1f)
                )
            }
        }
    }
}

@Composable
fun ToolButton(
    tool: DrawingTool,
    isSelected: Boolean,
    onClick: () -> Unit
) {
    val (icon, label) = when (tool) {
        DrawingTool.PEN -> Icons.Default.Edit to "Pen"
        DrawingTool.ARROW -> Icons.Default.ArrowForward to "Arrow"
        DrawingTool.CIRCLE -> Icons.Default.Circle to "Circle"
        DrawingTool.RECTANGLE -> Icons.Default.Rectangle to "Rect"
        DrawingTool.TEXT -> Icons.Default.TextFields to "Text"
        DrawingTool.MEASUREMENT -> Icons.Default.Straighten to "Measure"
    }

    IconButton(
        onClick = onClick,
        modifier = Modifier
            .background(
                if (isSelected) MaterialTheme.colorScheme.primaryContainer else Color.Transparent,
                RoundedCornerShape(8.dp)
            )
            .padding(8.dp)
    ) {
        Icon(
            icon,
            contentDescription = label,
            tint = if (isSelected) MaterialTheme.colorScheme.onPrimaryContainer else MaterialTheme.colorScheme.onSurface
        )
    }
}

@Composable
fun ColorButton(
    color: Color,
    isSelected: Boolean,
    onClick: () -> Unit
) {
    IconButton(
        onClick = onClick,
        modifier = Modifier
            .size(40.dp)
            .background(color, RoundedCornerShape(8.dp))
            .then(
                if (isSelected) {
                    Modifier
                } else {
                    Modifier
                }
            )
    ) {
        if (isSelected) {
            Icon(
                Icons.Default.Check,
                contentDescription = "Selected",
                tint = if (color.luminance() > 0.5f) Color.Black else Color.White
            )
        }
    }
}

enum class DrawingTool {
    PEN,
    ARROW,
    CIRCLE,
    RECTANGLE,
    TEXT,
    MEASUREMENT
}
package com.companycam.clone.ui.screens

import android.Manifest
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState

@OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class)
@Composable
fun PermitScannerScreen(
    navController: NavHostController,
    viewModel: PermitScannerViewModel = hiltViewModel()
) {
    val scanResult by viewModel.scanResult.collectAsState()
    val isScanning by viewModel.isScanning.collectAsState()
    val error by viewModel.error.collectAsState()

    val cameraPermissionState = rememberMultiplePermissionsState(
        permissions = listOf(
            Manifest.permission.CAMERA,
            Manifest.permission.ACCESS_FINE_LOCATION
        )
    )

    LaunchedEffect(scanResult) {
        scanResult?.let { result ->
            if (result.isSuccess) {
                // Auto-create project from permit
                viewModel.createProjectFromPermit(result.getOrNull()) { projectId ->
                    navController.navigate("projects/$projectId") {
                        popUpTo("projects")
                    }
                }
            }
        }
    }

    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text("Scan Building Permit") },
                navigationIcon = {
                    IconButton(onClick = { navController.navigateUp() }) {
                        Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
                    }
                }
            )
        }
    ) { paddingValues ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.spacedBy(16.dp)
        ) {
            if (cameraPermissionState.allPermissionsGranted) {
                if (isScanning) {
                    Box(
                        modifier = Modifier.fillMaxWidth(),
                        contentAlignment = Alignment.Center
                    ) {
                        Column(
                            horizontalAlignment = Alignment.CenterHorizontally,
                            verticalArrangement = Arrangement.spacedBy(16.dp)
                        ) {
                            CircularProgressIndicator()
                            Text(
                                text = "Scanning permit...",
                                style = MaterialTheme.typography.bodyLarge
                            )
                        }
                    }
                } else {
                    Card(
                        modifier = Modifier.fillMaxWidth(),
                        colors = CardDefaults.cardColors(
                            containerColor = MaterialTheme.colorScheme.surfaceVariant
                        )
                    ) {
                        Column(
                            modifier = Modifier.padding(24.dp),
                            horizontalAlignment = Alignment.CenterHorizontally,
                            verticalArrangement = Arrangement.spacedBy(16.dp)
                        ) {
                            Icon(
                                Icons.Default.DocumentScanner,
                                contentDescription = null,
                                modifier = Modifier.size(64.dp),
                                tint = MaterialTheme.colorScheme.primary
                            )
                            Text(
                                text = "Scan Building Permit",
                                style = MaterialTheme.typography.titleLarge,
                                fontWeight = FontWeight.Bold
                            )
                            Text(
                                text = "Position the permit within the frame. The app will automatically extract the address, client name, and permit number.",
                                style = MaterialTheme.typography.bodyMedium,
                                color = MaterialTheme.colorScheme.onSurfaceVariant
                            )
                            Button(
                                onClick = { viewModel.startScan() },
                                modifier = Modifier.fillMaxWidth()
                            ) {
                                Text("Start Camera Scan")
                            }
                        }
                    }
                }

                // Error message
                error?.let { errorMsg ->
                    Snackbar(
                        modifier = Modifier.padding(16.dp),
                        action = {
                            TextButton(onClick = { viewModel.clearError() }) {
                                Text("Dismiss")
                            }
                        }
                    ) {
                        Text(errorMsg)
                    }
                }
            } else {
                PermissionRequestContent(
                    onRequestPermission = {
                        cameraPermissionState.launchMultiplePermissionRequest()
                    }
                )
            }

            // Manual entry option
            OutlinedButton(
                onClick = { navController.navigate("projects/new") },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text("Enter Details Manually")
            }
        }
    }
}

@Composable
fun PermissionRequestContent(
    onRequestPermission: () -> Unit
) {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        Icon(
            Icons.Default.CameraAlt,
            contentDescription = null,
            modifier = Modifier.size(64.dp),
            tint = MaterialTheme.colorScheme.primary
        )
        Text(
            text = "Camera Permission Required",
            style = MaterialTheme.typography.titleLarge,
            fontWeight = FontWeight.Bold
        )
        Text(
            text = "Camera permission is needed to scan building permits.",
            style = MaterialTheme.typography.bodyMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant
        )
        Button(onClick = onRequestPermission) {
            Text("Grant Permission")
        }
    }
}


**Addressing Import Issues**

I'm now focusing on import discrepancies in `PermitScannerScreen.kt`. The initial concern about `Icons.Default.DocumentScanner` seems unfounded, as it *does* exist in `material-icons-extended`. However, the import structure might be the source of the trouble. I'm checking that now.

**Resolving Icon Conflicts**

I've swapped the problematic icon for `Icons.Default.Camera`. Also, it turns out that `DocumentScanner` should be available since I'm on 1.6.2. I'm focusing on the import, though it seems it's either in `filled` or missing. I also tried and confirmed `Icons.Default.Description`.

cat > android/app/src/main/java/com/companycam/clone/ui/screens/camera/CameraScreen.kt <<EOF
package com.companycam.clone.ui.screens.camera

import android.Manifest
import android.content.Context
import android.net.Uri
import androidx.camera.core.*
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.*
import androidx.camera.view.PreviewView
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.content.ContextCompat
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import com.companycam.clone.util.ExifUtils
import com.companycam.clone.util.LocationManager
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
import javax.inject.Inject

@OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class)
@Composable
fun CameraScreen(
    navController: NavHostController,
    projectId: Long? = null,
    viewModel: CameraViewModel = hiltViewModel()
) {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current

    var lensFacing by remember { mutableStateOf(CameraSelector.LENS_FACING_BACK) }
    var flashMode by remember { mutableStateOf(FlashMode.OFF) }
    var isRecording by remember { mutableStateOf(false) }

    val permissionsState = rememberMultiplePermissionsState(
        permissions = listOf(
            Manifest.permission.CAMERA,
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.ACCESS_FINE_LOCATION
        )
    )

    val cameraState by viewModel.cameraState.collectAsState()

    LaunchedEffect(Unit) {
        if (!permissionsState.allPermissionsGranted) {
            permissionsState.launchMultiplePermissionRequest()
        }
    }

    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text(getProjectTitle(projectId)) },
                navigationIcon = {
                    IconButton(onClick = { navController.navigateUp() }) {
                        Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
                    }
                },
                actions = {
                    // Flash toggle
                    IconButton(
                        onClick = {
                            flashMode = when (flashMode) {
                                FlashMode.ON -> FlashMode.OFF
                                FlashMode.OFF -> FlashMode.AUTO
                                FlashMode.AUTO -> FlashMode.ON
                            }
                        }
                    ) {
                        Icon(
                            when (flashMode) {
                                FlashMode.ON -> Icons.Default.FlashOn
                                FlashMode.OFF -> Icons.Default.FlashOff
                                FlashMode.AUTO -> Icons.Default.FlashAuto
                            },
                            contentDescription = "Flash"
                        )
                    }

                    // More options
                    IconButton(onClick = { /* Show menu */ }) {
                        Icon(Icons.Default.MoreVert, contentDescription = "More")
                    }
                }
            )
        }
    ) { paddingValues ->
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
        ) {
            if (permissionsState.allPermissionsGranted) {
                CameraPreview(
                    onImageCaptured = { imageCapture ->
                        viewModel.capturePhoto(
                            context = context,
                            imageCapture = imageCapture,
                            projectId = projectId,
                            onResult = { photoId ->
                                navController.navigate("photos/\$photoId/edit")
                            }
                        )
                    },
                    onVideoRecording = { videoCapture, isStarting ->
                        // Handle video recording
                    },
                    lensFacing = lensFacing,
                    flashMode = flashMode,
                    modifier = Modifier.fillMaxSize()
                )

                // Camera controls overlay
                CameraControls(
                    onSwitchCamera = {
                        lensFacing = if (lensFacing == CameraSelector.LENS_FACING_BACK) {
                            CameraSelector.LENS_FACING_FRONT
                        } else {
                            CameraSelector.LENS_FACING_BACK
                        }
                    },
                    onCapturePhoto = {
                        viewModel.triggerCapture()
                    },
                    isRecording = isRecording,
                    modifier = Modifier
                        .fillMaxWidth()
                        .align(Alignment.BottomCenter)
                        .padding(24.dp)
                )
            } else {
                PermissionRequestContent(
                    onRequestPermission = {
                        permissionsState.launchMultiplePermissionRequest()
                    },
                    modifier = Modifier.align(Alignment.Center)
                )
            }
        }
    }
}

@Composable
fun CameraPreview(
    onImageCaptured: (ImageCapture) -> Unit,
    onVideoRecording: (VideoCapture<Recorder>, Boolean) -> Unit,
    lensFacing: Int,
    flashMode: FlashMode,
    modifier: Modifier = Modifier
) {
    val context = LocalContext.current
    val lifecycleOwner = LocalLifecycleOwner.current

    var previewView by remember { mutableStateOf<PreviewView?>(null) }
    var imageCapture by remember { mutableStateOf<ImageCapture?>(null) }

    // Trigger capture when requested
    LaunchedEffect(imageCapture) {
        // This will be triggered by parent via a callback
        // But for now we are just setting it up
    }

    // We need to expose imageCapture to parent, but this composable doesn't have a way to return it easily
    // without a state holder. For now, we rely on viewModel.triggerCapture mechanism or similar?
    // Actually, viewModel.capturePhoto takes imageCapture as arg.
    // So we need to pass it up.
    // Let's use a side effect.
    DisposableEffect(imageCapture) {
        if (imageCapture != null) {
            onImageCaptured(imageCapture!!)
        }
        onDispose {}
    }

    AndroidView(
        factory = { ctx ->
            PreviewView(ctx).apply {
                previewView = this

                val cameraProviderFuture = ProcessCameraProvider.getInstance(ctx)
                cameraProviderFuture.addListener({
                    val cameraProvider = cameraProviderFuture.get()

                    val preview = Preview.Builder()
                        .build()
                        .also {
                            it.setSurfaceProvider(surfaceProvider)
                        }

                    val flashModeInt = when(flashMode) {
                        FlashMode.ON -> ImageCapture.FLASH_MODE_ON
                        FlashMode.OFF -> ImageCapture.FLASH_MODE_OFF
                        FlashMode.AUTO -> ImageCapture.FLASH_MODE_AUTO
                    }

                    imageCapture = ImageCapture.Builder()
                        .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                        .setFlashMode(flashModeInt)
                        .build()

                    val cameraSelector = CameraSelector.Builder()
                        .requireLensFacing(lensFacing)
                        .build()

                    try {
                        cameraProvider.unbindAll()
                        cameraProvider.bindToLifecycle(
                            lifecycleOwner,
                            cameraSelector,
                            preview,
                            imageCapture
                        )
                    } catch (e: Exception) {
                        e.printStackTrace()
                    }
                }, ContextCompat.getMainExecutor(ctx))
            }
        },
        modifier = modifier
    )
}

@Composable
fun CameraControls(
    onSwitchCamera: () -> Unit,
    onCapturePhoto: () -> Unit,
    isRecording: Boolean,
    modifier: Modifier = Modifier
) {
    Row(
        modifier = modifier,
        horizontalArrangement = Arrangement.SpaceAround,
        verticalAlignment = Alignment.CenterVertically
    ) {
        // Gallery thumbnail
        IconButton(
            onClick = { /* Open gallery */ },
            modifier = Modifier
                .size(56.dp)
                .clip(RoundedCornerShape(8.dp))
        ) {
            Icon(
                Icons.Default.PhotoLibrary,
                contentDescription = "Gallery",
                modifier = Modifier.size(32.dp)
            )
        }

        // Capture button
        IconButton(
            onClick = onCapturePhoto,
            modifier = Modifier.size(80.dp)
        ) {
            Box(
                modifier = Modifier
                    .size(72.dp)
                    .background(Color.White, CircleShape)
                    .padding(4.dp)
            ) {
                Box(
                    modifier = Modifier
                        .fillMaxSize()
                        .background(Color.Black, CircleShape)
                )
            }
        }

        // Switch camera / Video toggle
        IconButton(onClick = onSwitchCamera) {
            Icon(
                Icons.Default.FlipCameraIos,
                contentDescription = "Switch Camera",
                modifier = Modifier.size(32.dp)
            )
        }
    }
}

@Composable
fun PermissionRequestContent(
    onRequestPermission: () -> Unit,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier.padding(32.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Icon(
            Icons.Default.Camera, // Changed from CameraAlt
            contentDescription = null,
            modifier = Modifier.size(64.dp),
            tint = MaterialTheme.colorScheme.primary
        )
        Spacer(modifier = Modifier.height(16.dp))
        Text(
            text = "Camera Permission Required",
            style = MaterialTheme.typography.titleLarge,
            fontWeight = FontWeight.Bold
        )
        Spacer(modifier = Modifier.height(8.dp))
        Text(
            text = "CompanyCam Clone needs camera, location, and microphone permissions to capture photos with metadata.",
            style = MaterialTheme.typography.bodyMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant
        )
        Spacer(modifier = Modifier.height(24.dp))
        Button(onClick = onRequestPermission) {
            Text("Grant Permissions")
        }
    }
}

fun getProjectTitle(projectId: Long?): String {
    return if (projectId != null) "Capture Photo" else "Select Project"
}

enum class FlashMode {
    ON,
    OFF,
    AUTO
}
EOF


cat > android/app/src/main/java/com/companycam/clone/ui/screens/PermitScannerScreen.kt <<EOF
package com.companycam.clone.ui.screens

import android.Manifest
import androidx.compose.foundation.layout.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import com.google.accompanist.permissions.ExperimentalPermissionsApi
import com.google.accompanist.permissions.rememberMultiplePermissionsState

@OptIn(ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class)
@Composable
fun PermitScannerScreen(
    navController: NavHostController,
    viewModel: PermitScannerViewModel = hiltViewModel()
) {
    val scanResult by viewModel.scanResult.collectAsState()
    val isScanning by viewModel.isScanning.collectAsState()
    val error by viewModel.error.collectAsState()

    val cameraPermissionState = rememberMultiplePermissionsState(
        permissions = listOf(
            Manifest.permission.CAMERA,
            Manifest.permission.ACCESS_FINE_LOCATION
        )
    )

    LaunchedEffect(scanResult) {
        scanResult?.let { result ->
            if (result.isSuccess) {
                // Auto-create project from permit
                viewModel.createProjectFromPermit(result.getOrNull()) { projectId ->
                    navController.navigate("projects/\$projectId") {
                        popUpTo("projects")
                    }
                }
            }
        }
    }

    Scaffold(
        topBar = {
            TopAppBar(
                title = { Text("Scan Building Permit") },
                navigationIcon = {
                    IconButton(onClick = { navController.navigateUp() }) {
                        Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
                    }
                }
            )
        }
    ) { paddingValues ->
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
                .padding(16.dp),
            horizontalAlignment = Alignment.CenterHorizontally,
            verticalArrangement = Arrangement.spacedBy(16.dp)
        ) {
            if (cameraPermissionState.allPermissionsGranted) {
                if (isScanning) {
                    Box(
                        modifier = Modifier.fillMaxWidth(),
                        contentAlignment = Alignment.Center
                    ) {
                        Column(
                            horizontalAlignment = Alignment.CenterHorizontally,
                            verticalArrangement = Arrangement.spacedBy(16.dp)
                        ) {
                            CircularProgressIndicator()
                            Text(
                                text = "Scanning permit...",
                                style = MaterialTheme.typography.bodyLarge
                            )
                        }
                    }
                } else {
                    Card(
                        modifier = Modifier.fillMaxWidth(),
                        colors = CardDefaults.cardColors(
                            containerColor = MaterialTheme.colorScheme.surfaceVariant
                        )
                    ) {
                        Column(
                            modifier = Modifier.padding(24.dp),
                            horizontalAlignment = Alignment.CenterHorizontally,
                            verticalArrangement = Arrangement.spacedBy(16.dp)
                        ) {
                            Icon(
                                Icons.Default.Description, // Changed from DocumentScanner
                                contentDescription = null,
                                modifier = Modifier.size(64.dp),
                                tint = MaterialTheme.colorScheme.primary
                            )
                            Text(
                                text = "Scan Building Permit",
                                style = MaterialTheme.typography.titleLarge,
                                fontWeight = FontWeight.Bold
                            )
                            Text(
                                text = "Position the permit within the frame. The app will automatically extract the address, client name, and permit number.",
                                style = MaterialTheme.typography.bodyMedium,
                                color = MaterialTheme.colorScheme.onSurfaceVariant
                            )
                            Button(
                                onClick = { viewModel.startScan() },
                                modifier = Modifier.fillMaxWidth()
                            ) {
                                Text("Start Camera Scan")
                            }
                        }
                    }
                }

                // Error message
                error?.let { errorMsg ->
                    Snackbar(
                        modifier = Modifier.padding(16.dp),
                        action = {
                            TextButton(onClick = { viewModel.clearError() }) {
                                Text("Dismiss")
                            }
                        }
                    ) {
                        Text(errorMsg)
                    }
                }
            } else {
                PermissionRequestContent(
                    onRequestPermission = {
                        cameraPermissionState.launchMultiplePermissionRequest()
                    }
                )
            }

            // Manual entry option
            OutlinedButton(
                onClick = { navController.navigate("projects/new") },
                modifier = Modifier.fillMaxWidth()
            ) {
                Text("Enter Details Manually")
            }
        }
    }
}

@Composable
fun PermissionRequestContent(
    onRequestPermission: () -> Unit
) {
    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(16.dp)
    ) {
        Icon(
            Icons.Default.Camera, // Changed from CameraAlt
            contentDescription = null,
            modifier = Modifier.size(64.dp),
            tint = MaterialTheme.colorScheme.primary
        )
        Text(
            text = "Camera Permission Required",
            style = MaterialTheme.typography.titleLarge,
            fontWeight = FontWeight.Bold
        )
        Text(
            text = "Camera permission is needed to scan building permits.",
            style = MaterialTheme.typography.bodyMedium,
            color = MaterialTheme.colorScheme.onSurfaceVariant
        )
        Button(onClick = onRequestPermission) {
            Text("Grant Permission")
        }
    }
}
EOF


cat > android/app/src/main/java/com/companycam/clone/ui/screens/camera/CameraViewModel.kt <<EOF
package com.companycam.clone.ui.screens.camera

import android.content.Context
import android.net.Uri
import androidx.camera.core.ImageCapture
import androidx.core.content.ContextCompat
import androidx.lifecycle.viewModelScope
import com.companycam.clone.data.repository.PhotoRepository
import com.companycam.clone.util.ExifUtils
import com.companycam.clone.util.LocationManager
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import java.io.File
import java.text.SimpleDateFormat
import java.util.Locale
import javax.inject.Inject

@HiltViewModel
class CameraViewModel @Inject constructor(
    private val photoRepository: PhotoRepository,
    private val locationManager: LocationManager
) : androidx.lifecycle.ViewModel() {

    private val _cameraState = MutableStateFlow(CameraState())
    val cameraState: StateFlow<CameraState> = _cameraState.asStateFlow()

    private var onCaptureResult: ((Long) -> Unit)? = null

    fun capturePhoto(
        context: Context,
        imageCapture: ImageCapture,
        projectId: Long?,
        onResult: (Long) -> Unit
    ) {
        onCaptureResult = onResult
        viewModelScope.launch {
            try {
                val location = locationManager.getCurrentLocation()
                val photoFile = photoRepository.createImageFile()

                val outputFileOptions = ImageCapture.OutputFileOptions.Builder(photoFile).build()

                imageCapture.takePicture(
                    outputFileOptions,
                    ContextCompat.getMainExecutor(context),
                    object : ImageCapture.OnImageSavedCallback {
                        override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                            viewModelScope.launch {
                                // Stamp EXIF metadata
                                ExifUtils.stampMetadata(
                                    file = photoFile,
                                    location = location,
                                    userId = "user_123", // Get from auth
                                    userName = "Current User"
                                )

                                // Create watermarked version
                                val watermarkFile = File(photoFile.parent, "watermarked_\${photoFile.name}")
                                ExifUtils.addWatermark(
                                    sourceFile = photoFile,
                                    outputFile = watermarkFile,
                                    userName = "Current User",
                                    location = location,
                                    context = context
                                )

                                // Save to database
                                val savedProjectId = projectId ?: 1L // Default to first project
                                val photoId = photoRepository.savePhoto(
                                    projectId = savedProjectId,
                                    localPath = watermarkFile.absolutePath,
                                    thumbnailPath = null,
                                    latitude = location?.latitude,
                                    longitude = location?.longitude,
                                    altitude = location?.altitude,
                                    capturedBy = "Current User",
                                    capturedByUserId = "user_123"
                                )

                                onCaptureResult?.invoke(photoId)
                            }
                        }

                        override fun onError(exception: ImageCapture.Exception) {
                            exception.printStackTrace()
                        }
                    }
                )
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    fun triggerCapture() {
        _cameraState.value = _cameraState.value.copy(
            shouldCapture = _cameraState.value.shouldCapture + 1
        )
    }
}

data class CameraState(
    val isProcessing: Boolean = false,
    val shouldCapture: Int = 0
)
EOF


cat > android/app/src/main/java/com/companycam/clone/ui/screens/media/PhotoDetailScreen.kt <<EOF
package com.companycam.clone.ui.screens.media

import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTransformGestures
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavHostController
import coil.compose.AsyncImage
import java.util.Locale

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PhotoDetailScreen(
    photoId: Long,
    navController: NavHostController,
    viewModel: PhotoDetailViewModel = hiltViewModel()
) {
    val photo by viewModel.photo.collectAsState()
    val annotations by viewModel.annotations.collectAsState()

    Scaffold(
        topBar = {
            TopAppBar(
                title = { },
                navigationIcon = {
                    IconButton(onClick = { navController.navigateUp() }) {
                        Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = "Back")
                    }
                },
                actions = {
                    IconButton(onClick = { navController.navigate("photos/\$photoId/edit") }) {
                        Icon(Icons.Default.Edit, contentDescription = "Edit")
                    }
                    IconButton(onClick = { viewModel.toggleAIAnalysis() }) {
                        Icon(Icons.Default.AutoAwesome, contentDescription = "AI Analysis")
                    }
                    IconButton(onClick = { /* Share */ }) {
                        Icon(Icons.Default.Share, contentDescription = "Share")
                    }
                    IconButton(onClick = { /* Delete */ }) {
                        Icon(Icons.Default.Delete, contentDescription = "Delete")
                    }
                },
                colors = TopAppBarDefaults.topAppBarColors(
                    containerColor = Color.Transparent
                )
            )
        }
    ) { paddingValues ->
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(paddingValues)
        ) {
            photo?.let { currentPhoto ->
                ZoomableImage(
                    imageUrl = currentPhoto.localPath,
                    modifier = Modifier.fillMaxSize()
                )

                // Photo info overlay at bottom
                PhotoInfoOverlay(
                    photo = currentPhoto,
                    modifier = Modifier
                        .align(Alignment.BottomCenter)
                        .fillMaxWidth()
                )
            }
        }
    }
}

@Composable
fun ZoomableImage(
    imageUrl: String,
    modifier: Modifier = Modifier
) {
    var scale by remember { mutableStateOf(1f) }
    var offset by remember { mutableStateOf(Offset.Zero) }

    AsyncImage(
        model = imageUrl,
        contentDescription = null,
        modifier = modifier
            .pointerInput(Unit) {
                detectTransformGestures { _, _, zoom, _ ->
                    scale = (scale * zoom).coerceIn(0.5f, 4f)
                }
            }
            .graphicsLayer {
                scaleX = scale
                scaleY = scale
                translationX = offset.x
                translationY = offset.y
            },
        contentScale = ContentScale.Fit
    )
}

@Composable
fun PhotoInfoOverlay(
    photo: com.companycam.clone.data.models.Photo,
    modifier: Modifier = Modifier
) {
    Column(
        modifier = modifier
            .background(Color.Black.copy(alpha = 0.7f))
            .padding(16.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        Row(
            modifier = Modifier.fillMaxWidth(),
            horizontalArrangement = Arrangement.SpaceBetween
        ) {
            Column {
                Text(
                    text = formatTimestamp(photo.capturedAt),
                    style = MaterialTheme.typography.bodyMedium,
                    color = Color.White
                )
                Text(
                    text = "By \${photo.capturedBy}",
                    style = MaterialTheme.typography.bodySmall,
                    color = Color.White.copy(alpha = 0.7f)
                )
            }

            if (photo.latitude != null && photo.longitude != null) {
                Surface(
                    color = Color.White.copy(alpha = 0.2f),
                    shape = RoundedCornerShape(8.dp)
                ) {
                    Row(
                        modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
                        verticalAlignment = Alignment.CenterVertically
                    ) {
                        Icon(
                            Icons.Default.LocationOn,
                            contentDescription = null,
                            tint = Color.White,
                            modifier = Modifier.size(16.dp)
                        )
                        Spacer(modifier = Modifier.width(4.dp))
                        Text(
                            text = "%.4f, %.4f".format(photo.latitude, photo.longitude),
                            style = MaterialTheme.typography.bodySmall,
                            color = Color.White
                        )
                    }
                }
            }
        }

        // AI Analysis badge
        if (!photo.aiAnalysis.isNullOrBlank()) {
            Surface(
                color = MaterialTheme.colorScheme.tertiary.copy(alpha = 0.8f),
                shape = RoundedCornerShape(8.dp)
            ) {
                Row(
                    modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
                    verticalArrangement = Arrangement.Center
                ) {
                    Icon(
                        Icons.Default.AutoAwesome,
                        contentDescription = null,
                        modifier = Modifier.size(16.dp),
                        tint = Color.White
                    )
                    Spacer(modifier = Modifier.width(8.dp))
                    Text(
                        text = "AI Analysis Available",
                        style = MaterialTheme.typography.labelMedium,
                        color = Color.White
                    )
                }
            }
        }

        // Before/After indicator
        if (photo.isBefore) {
            Surface(
                color = Color(0xFFFF6D00).copy(alpha = 0.8f),
                shape = RoundedCornerShape(8.dp)
            ) {
                Text(
                    text = "BEFORE PHOTO",
                    modifier = Modifier.padding(horizontal = 12.dp, vertical = 6.dp),
                    style = MaterialTheme.typography.labelMedium,
                    color = Color.White
                )
            }
        }
    }
}

fun formatTimestamp(timestamp: Long): String {
    val sdf = java.text.SimpleDateFormat("MMM dd, yyyy • h:mm a", Locale.US)
    return sdf.format(java.util.Date(timestamp))
}
EOF